KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > core > hierarchy > TypeHierarchy


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 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.jdt.internal.core.hierarchy;
12
13 import java.io.IOException JavaDoc;
14 import java.io.InputStream JavaDoc;
15 import java.io.OutputStream JavaDoc;
16 import java.util.ArrayList JavaDoc;
17 import java.util.HashMap JavaDoc;
18 import java.util.Hashtable JavaDoc;
19 import java.util.Iterator JavaDoc;
20 import java.util.Map JavaDoc;
21
22 import org.eclipse.core.runtime.CoreException;
23 import org.eclipse.core.runtime.IPath;
24 import org.eclipse.core.runtime.IProgressMonitor;
25 import org.eclipse.core.runtime.ISafeRunnable;
26 import org.eclipse.core.runtime.IStatus;
27 import org.eclipse.core.runtime.OperationCanceledException;
28 import org.eclipse.core.runtime.SafeRunner;
29 import org.eclipse.jdt.core.*;
30 import org.eclipse.jdt.core.search.IJavaSearchScope;
31 import org.eclipse.jdt.core.search.SearchEngine;
32 import org.eclipse.jdt.internal.core.*;
33 import org.eclipse.jdt.internal.core.util.Messages;
34 import org.eclipse.jdt.internal.core.util.Util;
35
36 /**
37  * @see ITypeHierarchy
38  */

39 public class TypeHierarchy implements ITypeHierarchy, IElementChangedListener {
40
41     public static boolean DEBUG = false;
42     
43     static final byte VERSION = 0x0000;
44     // SEPARATOR
45
static final byte SEPARATOR1 = '\n';
46     static final byte SEPARATOR2 = ',';
47     static final byte SEPARATOR3 = '>';
48     static final byte SEPARATOR4 = '\r';
49     // general info
50
static final byte COMPUTE_SUBTYPES = 0x0001;
51     
52     // type info
53
static final byte CLASS = 0x0000;
54     static final byte INTERFACE = 0x0001;
55     static final byte COMPUTED_FOR = 0x0002;
56     static final byte ROOT = 0x0004;
57
58     // cst
59
static final byte[] NO_FLAGS = new byte[]{};
60     static final int SIZE = 10;
61     
62     /**
63      * The Java Project in which the hierarchy is being built - this
64      * provides the context for determining a classpath and namelookup rules.
65      * Possibly null.
66      */

67     protected IJavaProject project;
68     /**
69      * The type the hierarchy was specifically computed for,
70      * possibly null.
71      */

72     protected IType focusType;
73     
74     /*
75      * The working copies that take precedence over original compilation units
76      */

77     protected ICompilationUnit[] workingCopies;
78
79     protected Map JavaDoc classToSuperclass;
80     protected Map JavaDoc typeToSuperInterfaces;
81     protected Map JavaDoc typeToSubtypes;
82     protected Map JavaDoc typeFlags;
83     protected TypeVector rootClasses = new TypeVector();
84     protected ArrayList JavaDoc interfaces = new ArrayList JavaDoc(10);
85     public ArrayList JavaDoc missingTypes = new ArrayList JavaDoc(4);
86     
87     protected static final IType[] NO_TYPE = new IType[0];
88     
89     /**
90      * The progress monitor to report work completed too.
91      */

92     protected IProgressMonitor progressMonitor = null;
93
94     /**
95      * Change listeners - null if no one is listening.
96      */

97     protected ArrayList JavaDoc changeListeners = null;
98
99     /*
100      * A map from Openables to ArrayLists of ITypes
101      */

102     public Map JavaDoc files = null;
103
104     /**
105      * A region describing the packages considered by this
106      * hierarchy. Null if not activated.
107      */

108     protected Region packageRegion = null;
109
110     /**
111      * A region describing the projects considered by this
112      * hierarchy. Null if not activated.
113      */

114     protected Region projectRegion = null;
115     
116     /**
117      * Whether this hierarchy should contains subtypes.
118      */

119     protected boolean computeSubtypes;
120
121     /**
122      * The scope this hierarchy should restrain itsef in.
123      */

124     IJavaSearchScope scope;
125     
126     /*
127      * Whether this hierarchy needs refresh
128      */

129     public boolean needsRefresh = true;
130     
131     /*
132      * Collects changes to types
133      */

134     protected ChangeCollector changeCollector;
135
136 /**
137  * Creates an empty TypeHierarchy
138  */

139 public TypeHierarchy() {
140     // Creates an empty TypeHierarchy
141
}
142 /**
143  * Creates a TypeHierarchy on the given type.
144  */

145 public TypeHierarchy(IType type, ICompilationUnit[] workingCopies, IJavaProject project, boolean computeSubtypes) {
146     this(type, workingCopies, SearchEngine.createJavaSearchScope(new IJavaElement[] {project}), computeSubtypes);
147     this.project = project;
148 }
149 /**
150  * Creates a TypeHierarchy on the given type.
151  */

152 public TypeHierarchy(IType type, ICompilationUnit[] workingCopies, IJavaSearchScope scope, boolean computeSubtypes) {
153     this.focusType = type == null ? null : (IType) ((JavaElement) type).unresolved(); // unsure the focus type is unresolved (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=92357)
154
this.workingCopies = workingCopies;
155     this.computeSubtypes = computeSubtypes;
156     this.scope = scope;
157 }
158 /**
159  * Initializes the file, package and project regions
160  */

161 protected void initializeRegions() {
162
163     IType[] allTypes = getAllTypes();
164     for (int i = 0; i < allTypes.length; i++) {
165         IType type = allTypes[i];
166         Openable o = (Openable) ((JavaElement) type).getOpenableParent();
167         if (o != null) {
168             ArrayList JavaDoc types = (ArrayList JavaDoc)this.files.get(o);
169             if (types == null) {
170                 types = new ArrayList JavaDoc();
171                 this.files.put(o, types);
172             }
173             types.add(type);
174         }
175         IPackageFragment pkg = type.getPackageFragment();
176         this.packageRegion.add(pkg);
177         IJavaProject declaringProject = type.getJavaProject();
178         if (declaringProject != null) {
179             this.projectRegion.add(declaringProject);
180         }
181         checkCanceled();
182     }
183 }
184 /**
185  * Adds all of the elements in the collection to the list if the
186  * element is not already in the list.
187  */

188 private void addAllCheckingDuplicates(ArrayList JavaDoc list, IType[] collection) {
189     for (int i = 0; i < collection.length; i++) {
190         IType element = collection[i];
191         if (!list.contains(element)) {
192             list.add(element);
193         }
194     }
195 }
196 /**
197  * Adds the type to the collection of interfaces.
198  */

199 protected void addInterface(IType type) {
200     this.interfaces.add(type);
201 }
202 /**
203  * Adds the type to the collection of root classes
204  * if the classes is not already present in the collection.
205  */

206 protected void addRootClass(IType type) {
207     if (this.rootClasses.contains(type)) return;
208     this.rootClasses.add(type);
209 }
210 /**
211  * Adds the given subtype to the type.
212  */

213 protected void addSubtype(IType type, IType subtype) {
214     TypeVector subtypes = (TypeVector)this.typeToSubtypes.get(type);
215     if (subtypes == null) {
216         subtypes = new TypeVector();
217         this.typeToSubtypes.put(type, subtypes);
218     }
219     if (!subtypes.contains(subtype)) {
220         subtypes.add(subtype);
221     }
222 }
223 /**
224  * @see ITypeHierarchy
225  */

226 public synchronized void addTypeHierarchyChangedListener(ITypeHierarchyChangedListener listener) {
227     ArrayList JavaDoc listeners = this.changeListeners;
228     if (listeners == null) {
229         this.changeListeners = listeners = new ArrayList JavaDoc();
230     }
231     
232     // register with JavaCore to get Java element delta on first listener added
233
if (listeners.size() == 0) {
234         JavaCore.addElementChangedListener(this);
235     }
236     
237     // add listener only if it is not already present
238
if (listeners.indexOf(listener) == -1) {
239         listeners.add(listener);
240     }
241 }
242 private static Integer JavaDoc bytesToFlags(byte[] bytes){
243     if(bytes != null && bytes.length > 0) {
244         return new Integer JavaDoc(new String JavaDoc(bytes));
245     } else {
246         return null;
247     }
248 }
249 /**
250  * cacheFlags.
251  */

252 public void cacheFlags(IType type, int flags) {
253     this.typeFlags.put(type, new Integer JavaDoc(flags));
254 }
255 /**
256  * Caches the handle of the superclass for the specified type.
257  * As a side effect cache this type as a subtype of the superclass.
258  */

259 protected void cacheSuperclass(IType type, IType superclass) {
260     if (superclass != null) {
261         this.classToSuperclass.put(type, superclass);
262         addSubtype(superclass, type);
263     }
264 }
265 /**
266  * Caches all of the superinterfaces that are specified for the
267  * type.
268  */

269 protected void cacheSuperInterfaces(IType type, IType[] superinterfaces) {
270     this.typeToSuperInterfaces.put(type, superinterfaces);
271     for (int i = 0; i < superinterfaces.length; i++) {
272         IType superinterface = superinterfaces[i];
273         if (superinterface != null) {
274             addSubtype(superinterface, type);
275         }
276     }
277 }
278 /**
279  * Checks with the progress monitor to see whether the creation of the type hierarchy
280  * should be canceled. Should be regularly called
281  * so that the user can cancel.
282  *
283  * @exception OperationCanceledException if cancelling the operation has been requested
284  * @see IProgressMonitor#isCanceled
285  */

286 protected void checkCanceled() {
287     if (this.progressMonitor != null && this.progressMonitor.isCanceled()) {
288         throw new OperationCanceledException();
289     }
290 }
291 /**
292  * Compute this type hierarchy.
293  */

294 protected void compute() throws JavaModelException, CoreException {
295     if (this.focusType != null) {
296         HierarchyBuilder builder =
297             new IndexBasedHierarchyBuilder(
298                 this,
299                 this.scope);
300         builder.build(this.computeSubtypes);
301     } // else a RegionBasedTypeHierarchy should be used
302
}
303 /**
304  * @see ITypeHierarchy
305  */

306 public boolean contains(IType type) {
307     // classes
308
if (this.classToSuperclass.get(type) != null) {
309         return true;
310     }
311
312     // root classes
313
if (this.rootClasses.contains(type)) return true;
314
315     // interfaces
316
if (this.interfaces.contains(type)) return true;
317     
318     return false;
319 }
320 /**
321  * Determines if the change effects this hierarchy, and fires
322  * change notification if required.
323  */

324 public void elementChanged(ElementChangedEvent event) {
325     // type hierarchy change has already been fired
326
if (this.needsRefresh) return;
327     
328     if (isAffected(event.getDelta())) {
329         this.needsRefresh = true;
330         fireChange();
331     }
332 }
333 /**
334  * @see ITypeHierarchy
335  */

336 public boolean exists() {
337     if (!this.needsRefresh) return true;
338     
339     return (this.focusType == null || this.focusType.exists()) && this.javaProject().exists();
340 }
341 /**
342  * Notifies listeners that this hierarchy has changed and needs
343  * refreshing. Note that listeners can be removed as we iterate
344  * through the list.
345  */

346 public void fireChange() {
347     ArrayList JavaDoc listeners = this.changeListeners;
348     if (listeners == null) {
349         return;
350     }
351     if (DEBUG) {
352         System.out.println("FIRING hierarchy change ["+Thread.currentThread()+"]"); //$NON-NLS-1$ //$NON-NLS-2$
353
if (this.focusType != null) {
354             System.out.println(" for hierarchy focused on " + ((JavaElement)this.focusType).toStringWithAncestors()); //$NON-NLS-1$
355
}
356     }
357     // clone so that a listener cannot have a side-effect on this list when being notified
358
listeners = (ArrayList JavaDoc)listeners.clone();
359     for (int i= 0; i < listeners.size(); i++) {
360         final ITypeHierarchyChangedListener listener= (ITypeHierarchyChangedListener)listeners.get(i);
361         SafeRunner.run(new ISafeRunnable() {
362             public void handleException(Throwable JavaDoc exception) {
363                 Util.log(exception, "Exception occurred in listener of Type hierarchy change notification"); //$NON-NLS-1$
364
}
365             public void run() throws Exception JavaDoc {
366                 listener.typeHierarchyChanged(TypeHierarchy.this);
367             }
368         });
369     }
370 }
371 private static byte[] flagsToBytes(Integer JavaDoc flags){
372     if(flags != null) {
373         return flags.toString().getBytes();
374     } else {
375         return NO_FLAGS;
376     }
377 }
378 /**
379  * @see ITypeHierarchy
380  */

381 public IType[] getAllClasses() {
382
383     TypeVector classes = this.rootClasses.copy();
384     for (Iterator JavaDoc iter = this.classToSuperclass.keySet().iterator(); iter.hasNext();){
385         classes.add((IType)iter.next());
386     }
387     return classes.elements();
388 }
389 /**
390  * @see ITypeHierarchy
391  */

392 public IType[] getAllInterfaces() {
393     IType[] collection= new IType[this.interfaces.size()];
394     this.interfaces.toArray(collection);
395     return collection;
396 }
397 /**
398  * @see ITypeHierarchy
399  */

400 public IType[] getAllSubtypes(IType type) {
401     return getAllSubtypesForType(type);
402 }
403 /**
404  * @see #getAllSubtypes(IType)
405  */

406 private IType[] getAllSubtypesForType(IType type) {
407     ArrayList JavaDoc subTypes = new ArrayList JavaDoc();
408     getAllSubtypesForType0(type, subTypes);
409     IType[] subClasses = new IType[subTypes.size()];
410     subTypes.toArray(subClasses);
411     return subClasses;
412 }
413 /**
414  */

415 private void getAllSubtypesForType0(IType type, ArrayList JavaDoc subs) {
416     IType[] subTypes = getSubtypesForType(type);
417     if (subTypes.length != 0) {
418         for (int i = 0; i < subTypes.length; i++) {
419             IType subType = subTypes[i];
420             subs.add(subType);
421             getAllSubtypesForType0(subType, subs);
422         }
423     }
424 }
425 /**
426  * @see ITypeHierarchy
427  */

428 public IType[] getAllSuperclasses(IType type) {
429     IType superclass = getSuperclass(type);
430     TypeVector supers = new TypeVector();
431     while (superclass != null) {
432         supers.add(superclass);
433         superclass = getSuperclass(superclass);
434     }
435     return supers.elements();
436 }
437 /**
438  * @see ITypeHierarchy
439  */

440 public IType[] getAllSuperInterfaces(IType type) {
441     ArrayList JavaDoc supers = new ArrayList JavaDoc();
442     if (this.typeToSuperInterfaces.get(type) == null) {
443         return NO_TYPE;
444     }
445     getAllSuperInterfaces0(type, supers);
446     IType[] superinterfaces = new IType[supers.size()];
447     supers.toArray(superinterfaces);
448     return superinterfaces;
449 }
450 private void getAllSuperInterfaces0(IType type, ArrayList JavaDoc supers) {
451     IType[] superinterfaces = (IType[]) this.typeToSuperInterfaces.get(type);
452     if (superinterfaces != null && superinterfaces.length != 0) {
453         addAllCheckingDuplicates(supers, superinterfaces);
454         for (int i = 0; i < superinterfaces.length; i++) {
455             getAllSuperInterfaces0(superinterfaces[i], supers);
456         }
457     }
458     IType superclass = (IType) this.classToSuperclass.get(type);
459     if (superclass != null) {
460         getAllSuperInterfaces0(superclass, supers);
461     }
462 }
463 /**
464  * @see ITypeHierarchy
465  */

466 public IType[] getAllSupertypes(IType type) {
467     ArrayList JavaDoc supers = new ArrayList JavaDoc();
468     if (this.typeToSuperInterfaces.get(type) == null) {
469         return NO_TYPE;
470     }
471     getAllSupertypes0(type, supers);
472     IType[] supertypes = new IType[supers.size()];
473     supers.toArray(supertypes);
474     return supertypes;
475 }
476 private void getAllSupertypes0(IType type, ArrayList JavaDoc supers) {
477     IType[] superinterfaces = (IType[]) this.typeToSuperInterfaces.get(type);
478     if (superinterfaces != null && superinterfaces.length != 0) {
479         addAllCheckingDuplicates(supers, superinterfaces);
480         for (int i = 0; i < superinterfaces.length; i++) {
481             getAllSuperInterfaces0(superinterfaces[i], supers);
482         }
483     }
484     IType superclass = (IType) this.classToSuperclass.get(type);
485     if (superclass != null) {
486         supers.add(superclass);
487         getAllSupertypes0(superclass, supers);
488     }
489 }
490 /**
491  * @see ITypeHierarchy
492  */

493 public IType[] getAllTypes() {
494     IType[] classes = getAllClasses();
495     int classesLength = classes.length;
496     IType[] allInterfaces = getAllInterfaces();
497     int interfacesLength = allInterfaces.length;
498     IType[] all = new IType[classesLength + interfacesLength];
499     System.arraycopy(classes, 0, all, 0, classesLength);
500     System.arraycopy(allInterfaces, 0, all, classesLength, interfacesLength);
501     return all;
502 }
503
504 /**
505  * @see ITypeHierarchy#getCachedFlags(IType)
506  */

507 public int getCachedFlags(IType type) {
508     Integer JavaDoc flagObject = (Integer JavaDoc) this.typeFlags.get(type);
509     if (flagObject != null){
510         return flagObject.intValue();
511     }
512     return -1;
513 }
514
515 /**
516  * @see ITypeHierarchy
517  */

518 public IType[] getExtendingInterfaces(IType type) {
519     if (!this.isInterface(type)) return NO_TYPE;
520     return getExtendingInterfaces0(type);
521 }
522 /**
523  * Assumes that the type is an interface
524  * @see #getExtendingInterfaces
525  */

526 private IType[] getExtendingInterfaces0(IType extendedInterface) {
527     Iterator JavaDoc iter = this.typeToSuperInterfaces.entrySet().iterator();
528     ArrayList JavaDoc interfaceList = new ArrayList JavaDoc();
529     while (iter.hasNext()) {
530         Map.Entry JavaDoc entry = (Map.Entry JavaDoc) iter.next();
531         IType type = (IType) entry.getKey();
532         if (!this.isInterface(type)) {
533             continue;
534         }
535         IType[] superInterfaces = (IType[]) entry.getValue();
536         if (superInterfaces != null) {
537             for (int i = 0; i < superInterfaces.length; i++) {
538                 IType superInterface = superInterfaces[i];
539                 if (superInterface.equals(extendedInterface)) {
540                     interfaceList.add(type);
541                 }
542             }
543         }
544     }
545     IType[] extendingInterfaces = new IType[interfaceList.size()];
546     interfaceList.toArray(extendingInterfaces);
547     return extendingInterfaces;
548 }
549 /**
550  * @see ITypeHierarchy
551  */

552 public IType[] getImplementingClasses(IType type) {
553     if (!this.isInterface(type)) {
554         return NO_TYPE;
555     }
556     return getImplementingClasses0(type);
557 }
558 /**
559  * Assumes that the type is an interface
560  * @see #getImplementingClasses
561  */

562 private IType[] getImplementingClasses0(IType interfce) {
563     
564     Iterator JavaDoc iter = this.typeToSuperInterfaces.entrySet().iterator();
565     ArrayList JavaDoc iMenters = new ArrayList JavaDoc();
566     while (iter.hasNext()) {
567         Map.Entry JavaDoc entry = (Map.Entry JavaDoc) iter.next();
568         IType type = (IType) entry.getKey();
569         if (this.isInterface(type)) {
570             continue;
571         }
572         IType[] types = (IType[]) entry.getValue();
573         for (int i = 0; i < types.length; i++) {
574             IType iFace = types[i];
575             if (iFace.equals(interfce)) {
576                 iMenters.add(type);
577             }
578         }
579     }
580     IType[] implementers = new IType[iMenters.size()];
581     iMenters.toArray(implementers);
582     return implementers;
583 }
584 /**
585  * @see ITypeHierarchy
586  */

587 public IType[] getRootClasses() {
588     return this.rootClasses.elements();
589 }
590 /**
591  * @see ITypeHierarchy
592  */

593 public IType[] getRootInterfaces() {
594     IType[] allInterfaces = getAllInterfaces();
595     IType[] roots = new IType[allInterfaces.length];
596     int rootNumber = 0;
597     for (int i = 0; i < allInterfaces.length; i++) {
598         IType[] superInterfaces = getSuperInterfaces(allInterfaces[i]);
599         if (superInterfaces == null || superInterfaces.length == 0) {
600             roots[rootNumber++] = allInterfaces[i];
601         }
602     }
603     IType[] result = new IType[rootNumber];
604     if (result.length > 0) {
605         System.arraycopy(roots, 0, result, 0, rootNumber);
606     }
607     return result;
608 }
609 /**
610  * @see ITypeHierarchy
611  */

612 public IType[] getSubclasses(IType type) {
613     if (this.isInterface(type)) {
614         return NO_TYPE;
615     }
616     TypeVector vector = (TypeVector)this.typeToSubtypes.get(type);
617     if (vector == null)
618         return NO_TYPE;
619     else
620         return vector.elements();
621 }
622 /**
623  * @see ITypeHierarchy
624  */

625 public IType[] getSubtypes(IType type) {
626     return getSubtypesForType(type);
627 }
628 /**
629  * Returns an array of subtypes for the given type - will never return null.
630  */

631 private IType[] getSubtypesForType(IType type) {
632     TypeVector vector = (TypeVector)this.typeToSubtypes.get(type);
633     if (vector == null)
634         return NO_TYPE;
635     else
636         return vector.elements();
637 }
638 /**
639  * @see ITypeHierarchy
640  */

641 public IType getSuperclass(IType type) {
642     if (this.isInterface(type)) {
643         return null;
644     }
645     return (IType) this.classToSuperclass.get(type);
646 }
647 /**
648  * @see ITypeHierarchy
649  */

650 public IType[] getSuperInterfaces(IType type) {
651     IType[] types = (IType[]) this.typeToSuperInterfaces.get(type);
652     if (types == null) {
653         return NO_TYPE;
654     }
655     return types;
656 }
657 /**
658  * @see ITypeHierarchy
659  */

660 public IType[] getSupertypes(IType type) {
661     IType superclass = getSuperclass(type);
662     if (superclass == null) {
663         return getSuperInterfaces(type);
664     } else {
665         TypeVector superTypes = new TypeVector(getSuperInterfaces(type));
666         superTypes.add(superclass);
667         return superTypes.elements();
668     }
669 }
670 /**
671  * @see ITypeHierarchy
672  */

673 public IType getType() {
674     return this.focusType;
675 }
676 /**
677  * Adds the new elements to a new array that contains all of the elements of the old array.
678  * Returns the new array.
679  */

680 protected IType[] growAndAddToArray(IType[] array, IType[] additions) {
681     if (array == null || array.length == 0) {
682         return additions;
683     }
684     IType[] old = array;
685     array = new IType[old.length + additions.length];
686     System.arraycopy(old, 0, array, 0, old.length);
687     System.arraycopy(additions, 0, array, old.length, additions.length);
688     return array;
689 }
690 /**
691  * Adds the new element to a new array that contains all of the elements of the old array.
692  * Returns the new array.
693  */

694 protected IType[] growAndAddToArray(IType[] array, IType addition) {
695     if (array == null || array.length == 0) {
696         return new IType[] {addition};
697     }
698     IType[] old = array;
699     array = new IType[old.length + 1];
700     System.arraycopy(old, 0, array, 0, old.length);
701     array[old.length] = addition;
702     return array;
703 }
704 /*
705  * Whether fine-grained deltas where collected and affects this hierarchy.
706  */

707 public boolean hasFineGrainChanges() {
708     ChangeCollector collector = this.changeCollector;
709     return collector != null && collector.needsRefresh();
710 }
711 /**
712  * Returns whether one of the subtypes in this hierarchy has the given simple name
713  * or this type has the given simple name.
714  */

715 private boolean hasSubtypeNamed(String JavaDoc simpleName) {
716     if (this.focusType != null && this.focusType.getElementName().equals(simpleName)) {
717         return true;
718     }
719     IType[] types = this.focusType == null ? getAllTypes() : getAllSubtypes(this.focusType);
720     for (int i = 0, length = types.length; i < length; i++) {
721         if (types[i].getElementName().equals(simpleName)) {
722             return true;
723         }
724     }
725     return false;
726 }
727
728 /**
729  * Returns whether one of the types in this hierarchy has the given simple name.
730  */

731 private boolean hasTypeNamed(String JavaDoc simpleName) {
732     IType[] types = this.getAllTypes();
733     for (int i = 0, length = types.length; i < length; i++) {
734         if (types[i].getElementName().equals(simpleName)) {
735             return true;
736         }
737     }
738     return false;
739 }
740
741 /**
742  * Returns whether the simple name of the given type or one of its supertypes is
743  * the simple name of one of the types in this hierarchy.
744  */

745 boolean includesTypeOrSupertype(IType type) {
746     try {
747         // check type
748
if (hasTypeNamed(type.getElementName())) return true;
749         
750         // check superclass
751
String JavaDoc superclassName = type.getSuperclassName();
752         if (superclassName != null) {
753             int lastSeparator = superclassName.lastIndexOf('.');
754             String JavaDoc simpleName = superclassName.substring(lastSeparator+1);
755             if (hasTypeNamed(simpleName)) return true;
756         }
757     
758         // check superinterfaces
759
String JavaDoc[] superinterfaceNames = type.getSuperInterfaceNames();
760         if (superinterfaceNames != null) {
761             for (int i = 0, length = superinterfaceNames.length; i < length; i++) {
762                 String JavaDoc superinterfaceName = superinterfaceNames[i];
763                 int lastSeparator = superinterfaceName.lastIndexOf('.');
764                 String JavaDoc simpleName = superinterfaceName.substring(lastSeparator+1);
765                 if (hasTypeNamed(simpleName)) return true;
766             }
767         }
768     } catch (JavaModelException e) {
769         // ignore
770
}
771     return false;
772 }
773 /**
774  * Initializes this hierarchy's internal tables with the given size.
775  */

776 protected void initialize(int size) {
777     if (size < 10) {
778         size = 10;
779     }
780     int smallSize = (size / 2);
781     this.classToSuperclass = new HashMap JavaDoc(size);
782     this.interfaces = new ArrayList JavaDoc(smallSize);
783     this.missingTypes = new ArrayList JavaDoc(smallSize);
784     this.rootClasses = new TypeVector();
785     this.typeToSubtypes = new HashMap JavaDoc(smallSize);
786     this.typeToSuperInterfaces = new HashMap JavaDoc(smallSize);
787     this.typeFlags = new HashMap JavaDoc(smallSize);
788     
789     this.projectRegion = new Region();
790     this.packageRegion = new Region();
791     this.files = new HashMap JavaDoc(5);
792 }
793 /**
794  * Returns true if the given delta could change this type hierarchy
795  */

796 public synchronized boolean isAffected(IJavaElementDelta delta) {
797     IJavaElement element= delta.getElement();
798     switch (element.getElementType()) {
799         case IJavaElement.JAVA_MODEL:
800             return isAffectedByJavaModel(delta, element);
801         case IJavaElement.JAVA_PROJECT:
802             return isAffectedByJavaProject(delta, element);
803         case IJavaElement.PACKAGE_FRAGMENT_ROOT:
804             return isAffectedByPackageFragmentRoot(delta, element);
805         case IJavaElement.PACKAGE_FRAGMENT:
806             return isAffectedByPackageFragment(delta, (PackageFragment) element);
807         case IJavaElement.CLASS_FILE:
808         case IJavaElement.COMPILATION_UNIT:
809             return isAffectedByOpenable(delta, element);
810     }
811     return false;
812 }
813 /**
814  * Returns true if any of the children of a project, package
815  * fragment root, or package fragment have changed in a way that
816  * effects this type hierarchy.
817  */

818 private boolean isAffectedByChildren(IJavaElementDelta delta) {
819     if ((delta.getFlags() & IJavaElementDelta.F_CHILDREN) > 0) {
820         IJavaElementDelta[] children= delta.getAffectedChildren();
821         for (int i= 0; i < children.length; i++) {
822             if (isAffected(children[i])) {
823                 return true;
824             }
825         }
826     }
827     return false;
828 }
829 /**
830  * Returns true if the given java model delta could affect this type hierarchy
831  */

832 private boolean isAffectedByJavaModel(IJavaElementDelta delta, IJavaElement element) {
833     switch (delta.getKind()) {
834         case IJavaElementDelta.ADDED :
835         case IJavaElementDelta.REMOVED :
836             return element.equals(this.javaProject().getJavaModel());
837         case IJavaElementDelta.CHANGED :
838             return isAffectedByChildren(delta);
839     }
840     return false;
841 }
842 /**
843  * Returns true if the given java project delta could affect this type hierarchy
844  */

845 private boolean isAffectedByJavaProject(IJavaElementDelta delta, IJavaElement element) {
846     int kind = delta.getKind();
847     int flags = delta.getFlags();
848     if ((flags & IJavaElementDelta.F_OPENED) != 0) {
849         kind = IJavaElementDelta.ADDED; // affected in the same way
850
}
851     if ((flags & IJavaElementDelta.F_CLOSED) != 0) {
852         kind = IJavaElementDelta.REMOVED; // affected in the same way
853
}
854     switch (kind) {
855         case IJavaElementDelta.ADDED :
856             try {
857                 // if the added project is on the classpath, then the hierarchy has changed
858
IClasspathEntry[] classpath = ((JavaProject)this.javaProject()).getExpandedClasspath();
859                 for (int i = 0; i < classpath.length; i++) {
860                     if (classpath[i].getEntryKind() == IClasspathEntry.CPE_PROJECT
861                             && classpath[i].getPath().equals(element.getPath())) {
862                         return true;
863                     }
864                 }
865                 if (this.focusType != null) {
866                     // if the hierarchy's project is on the added project classpath, then the hierarchy has changed
867
classpath = ((JavaProject)element).getExpandedClasspath();
868                     IPath hierarchyProject = javaProject().getPath();
869                     for (int i = 0; i < classpath.length; i++) {
870                         if (classpath[i].getEntryKind() == IClasspathEntry.CPE_PROJECT
871                                 && classpath[i].getPath().equals(hierarchyProject)) {
872                             return true;
873                         }
874                     }
875                 }
876                 return false;
877             } catch (JavaModelException e) {
878                 return false;
879             }
880         case IJavaElementDelta.REMOVED :
881             // removed project - if it contains packages we are interested in
882
// then the type hierarchy has changed
883
IJavaElement[] pkgs = this.packageRegion.getElements();
884             for (int i = 0; i < pkgs.length; i++) {
885                 IJavaProject javaProject = pkgs[i].getJavaProject();
886                 if (javaProject != null && javaProject.equals(element)) {
887                     return true;
888                 }
889             }
890             return false;
891         case IJavaElementDelta.CHANGED :
892             return isAffectedByChildren(delta);
893     }
894     return false;
895 }
896 /**
897  * Returns true if the given package fragment delta could affect this type hierarchy
898  */

899 private boolean isAffectedByPackageFragment(IJavaElementDelta delta, PackageFragment element) {
900     switch (delta.getKind()) {
901         case IJavaElementDelta.ADDED :
902             // if the package fragment is in the projects being considered, this could
903
// introduce new types, changing the hierarchy
904
return this.projectRegion.contains(element);
905         case IJavaElementDelta.REMOVED :
906             // is a change if the package fragment contains types in this hierarchy
907
return packageRegionContainsSamePackageFragment(element);
908         case IJavaElementDelta.CHANGED :
909             // look at the files in the package fragment
910
return isAffectedByChildren(delta);
911     }
912     return false;
913 }
914 /**
915  * Returns true if the given package fragment root delta could affect this type hierarchy
916  */

917 private boolean isAffectedByPackageFragmentRoot(IJavaElementDelta delta, IJavaElement element) {
918     switch (delta.getKind()) {
919         case IJavaElementDelta.ADDED :
920             return this.projectRegion.contains(element);
921         case IJavaElementDelta.REMOVED :
922         case IJavaElementDelta.CHANGED :
923             int flags = delta.getFlags();
924             if ((flags & IJavaElementDelta.F_ADDED_TO_CLASSPATH) > 0) {
925                 // check if the root is in the classpath of one of the projects of this hierarchy
926
if (this.projectRegion != null) {
927                     IPackageFragmentRoot root = (IPackageFragmentRoot)element;
928                     IPath rootPath = root.getPath();
929                     IJavaElement[] elements = this.projectRegion.getElements();
930                     for (int i = 0; i < elements.length; i++) {
931                         JavaProject javaProject = (JavaProject)elements[i];
932                         try {
933                             IClasspathEntry entry = javaProject.getClasspathEntryFor(rootPath);
934                             if (entry != null) {
935                                 return true;
936                             }
937                         } catch (JavaModelException e) {
938                             // igmore this project
939
}
940                     }
941                 }
942             }
943             if ((flags & IJavaElementDelta.F_REMOVED_FROM_CLASSPATH) > 0 || (flags & IJavaElementDelta.F_CONTENT) > 0) {
944                 // 1. removed from classpath - if it contains packages we are interested in
945
// the the type hierarchy has changed
946
// 2. content of a jar changed - if it contains packages we are interested in
947
// the the type hierarchy has changed
948
IJavaElement[] pkgs = this.packageRegion.getElements();
949                 for (int i = 0; i < pkgs.length; i++) {
950                     if (pkgs[i].getParent().equals(element)) {
951                         return true;
952                     }
953                 }
954                 return false;
955             }
956     }
957     return isAffectedByChildren(delta);
958 }
959 /**
960  * Returns true if the given type delta (a compilation unit delta or a class file delta)
961  * could affect this type hierarchy.
962  */

963 protected boolean isAffectedByOpenable(IJavaElementDelta delta, IJavaElement element) {
964     if (element instanceof CompilationUnit) {
965         CompilationUnit cu = (CompilationUnit)element;
966         ChangeCollector collector = this.changeCollector;
967         if (collector == null) {
968             collector = new ChangeCollector(this);
969         }
970         try {
971             collector.addChange(cu, delta);
972         } catch (JavaModelException e) {
973             if (DEBUG)
974                 e.printStackTrace();
975         }
976         if (cu.isWorkingCopy()) {
977             // changes to working copies are batched
978
this.changeCollector = collector;
979             return false;
980         } else {
981             return collector.needsRefresh();
982         }
983     } else if (element instanceof ClassFile) {
984         switch (delta.getKind()) {
985             case IJavaElementDelta.REMOVED:
986                 return this.files.get(element) != null;
987             case IJavaElementDelta.ADDED:
988                 IType type = ((ClassFile)element).getType();
989                 String JavaDoc typeName = type.getElementName();
990                 if (hasSupertype(typeName)
991                     || subtypesIncludeSupertypeOf(type)
992                     || this.missingTypes.contains(typeName)) {
993                         
994                     return true;
995                 }
996                 break;
997             case IJavaElementDelta.CHANGED:
998                 IJavaElementDelta[] children = delta.getAffectedChildren();
999                 for (int i = 0, length = children.length; i < length; i++) {
1000                    IJavaElementDelta child = children[i];
1001                    IJavaElement childElement = child.getElement();
1002                    if (childElement instanceof IType) {
1003                        type = (IType)childElement;
1004                        boolean hasVisibilityChange = (delta.getFlags() & IJavaElementDelta.F_MODIFIERS) > 0;
1005                        boolean hasSupertypeChange = (delta.getFlags() & IJavaElementDelta.F_SUPER_TYPES) > 0;
1006                        if ((hasVisibilityChange && hasSupertype(type.getElementName()))
1007                                || (hasSupertypeChange && includesTypeOrSupertype(type))) {
1008                            return true;
1009                        }
1010                    }
1011                }
1012                break;
1013        }
1014    }
1015    return false;
1016}
1017private boolean isInterface(IType type) {
1018    int flags = this.getCachedFlags(type);
1019    if (flags == -1) {
1020        try {
1021            return type.isInterface();
1022        } catch (JavaModelException e) {
1023            return false;
1024        }
1025    } else {
1026        return Flags.isInterface(flags);
1027    }
1028}
1029/**
1030 * Returns the java project this hierarchy was created in.
1031 */

1032public IJavaProject javaProject() {
1033    return this.focusType.getJavaProject();
1034}
1035protected static byte[] readUntil(InputStream JavaDoc input, byte separator) throws JavaModelException, IOException JavaDoc{
1036    return readUntil(input, separator, 0);
1037}
1038protected static byte[] readUntil(InputStream JavaDoc input, byte separator, int offset) throws IOException JavaDoc, JavaModelException{
1039    int length = 0;
1040    byte[] bytes = new byte[SIZE];
1041    byte b;
1042    while((b = (byte)input.read()) != separator && b != -1) {
1043        if(bytes.length == length) {
1044            System.arraycopy(bytes, 0, bytes = new byte[length*2], 0, length);
1045        }
1046        bytes[length++] = b;
1047    }
1048    if(b == -1) {
1049        throw new JavaModelException(new JavaModelStatus(IStatus.ERROR));
1050    }
1051    System.arraycopy(bytes, 0, bytes = new byte[length + offset], offset, length);
1052    return bytes;
1053}
1054public static ITypeHierarchy load(IType type, InputStream JavaDoc input, WorkingCopyOwner owner) throws JavaModelException {
1055    try {
1056        TypeHierarchy typeHierarchy = new TypeHierarchy();
1057        typeHierarchy.initialize(1);
1058        
1059        IType[] types = new IType[SIZE];
1060        int typeCount = 0;
1061        
1062        byte version = (byte)input.read();
1063    
1064        if(version != VERSION) {
1065            throw new JavaModelException(new JavaModelStatus(IStatus.ERROR));
1066        }
1067        byte generalInfo = (byte)input.read();
1068        if((generalInfo & COMPUTE_SUBTYPES) != 0) {
1069            typeHierarchy.computeSubtypes = true;
1070        }
1071        
1072        byte b;
1073        byte[] bytes;
1074        
1075        // read project
1076
bytes = readUntil(input, SEPARATOR1);
1077        if(bytes.length > 0) {
1078            typeHierarchy.project = (IJavaProject)JavaCore.create(new String JavaDoc(bytes));
1079            typeHierarchy.scope = SearchEngine.createJavaSearchScope(new IJavaElement[] {typeHierarchy.project});
1080        } else {
1081            typeHierarchy.project = null;
1082            typeHierarchy.scope = SearchEngine.createWorkspaceScope();
1083        }
1084        
1085        // read missing type
1086
{
1087            bytes = readUntil(input, SEPARATOR1);
1088            byte[] missing;
1089            int j = 0;
1090            int length = bytes.length;
1091            for (int i = 0; i < length; i++) {
1092                b = bytes[i];
1093                if(b == SEPARATOR2) {
1094                    missing = new byte[i - j];
1095                    System.arraycopy(bytes, j, missing, 0, i - j);
1096                    typeHierarchy.missingTypes.add(new String JavaDoc(missing));
1097                    j = i + 1;
1098                }
1099            }
1100            System.arraycopy(bytes, j, missing = new byte[length - j], 0, length - j);
1101            typeHierarchy.missingTypes.add(new String JavaDoc(missing));
1102        }
1103
1104        // read types
1105
while((b = (byte)input.read()) != SEPARATOR1 && b != -1) {
1106            bytes = readUntil(input, SEPARATOR4, 1);
1107            bytes[0] = b;
1108            IType element = (IType)JavaCore.create(new String JavaDoc(bytes), owner);
1109            
1110            if(types.length == typeCount) {
1111                System.arraycopy(types, 0, types = new IType[typeCount * 2], 0, typeCount);
1112            }
1113            types[typeCount++] = element;
1114            
1115            // read flags
1116
bytes = readUntil(input, SEPARATOR4);
1117            Integer JavaDoc flags = bytesToFlags(bytes);
1118            if(flags != null) {
1119                typeHierarchy.cacheFlags(element, flags.intValue());
1120            }
1121            
1122            // read info
1123
byte info = (byte)input.read();
1124            
1125            if((info & INTERFACE) != 0) {
1126                typeHierarchy.addInterface(element);
1127            }
1128            if((info & COMPUTED_FOR) != 0) {
1129                if(!element.equals(type)) {
1130                    throw new JavaModelException(new JavaModelStatus(IStatus.ERROR));
1131                }
1132                typeHierarchy.focusType = element;
1133            }
1134            if((info & ROOT) != 0) {
1135                typeHierarchy.addRootClass(element);
1136            }
1137        }
1138        
1139        // read super class
1140
while((b = (byte)input.read()) != SEPARATOR1 && b != -1) {
1141            bytes = readUntil(input, SEPARATOR3, 1);
1142            bytes[0] = b;
1143            int subClass = new Integer JavaDoc(new String JavaDoc(bytes)).intValue();
1144            
1145            // read super type
1146
bytes = readUntil(input, SEPARATOR1);
1147            int superClass = new Integer JavaDoc(new String JavaDoc(bytes)).intValue();
1148            
1149            typeHierarchy.cacheSuperclass(
1150                types[subClass],
1151                types[superClass]);
1152        }
1153        
1154        // read super interface
1155
while((b = (byte)input.read()) != SEPARATOR1 && b != -1) {
1156            bytes = readUntil(input, SEPARATOR3, 1);
1157            bytes[0] = b;
1158            int subClass = new Integer JavaDoc(new String JavaDoc(bytes)).intValue();
1159            
1160            // read super interface
1161
bytes = readUntil(input, SEPARATOR1);
1162            IType[] superInterfaces = new IType[(bytes.length / 2) + 1];
1163            int interfaceCount = 0;
1164            
1165            int j = 0;
1166            byte[] b2;
1167            for (int i = 0; i < bytes.length; i++) {
1168                if(bytes[i] == SEPARATOR2){
1169                    b2 = new byte[i - j];
1170                    System.arraycopy(bytes, j, b2, 0, i - j);
1171                    j = i + 1;
1172                    superInterfaces[interfaceCount++] = types[new Integer JavaDoc(new String JavaDoc(b2)).intValue()];
1173                }
1174            }
1175            b2 = new byte[bytes.length - j];
1176            System.arraycopy(bytes, j, b2, 0, bytes.length - j);
1177            superInterfaces[interfaceCount++] = types[new Integer JavaDoc(new String JavaDoc(b2)).intValue()];
1178            System.arraycopy(superInterfaces, 0, superInterfaces = new IType[interfaceCount], 0, interfaceCount);
1179            
1180            typeHierarchy.cacheSuperInterfaces(
1181                types[subClass],
1182                superInterfaces);
1183        }
1184        if(b == -1) {
1185            throw new JavaModelException(new JavaModelStatus(IStatus.ERROR));
1186        }
1187        return typeHierarchy;
1188    } catch(IOException JavaDoc e){
1189        throw new JavaModelException(e, IJavaModelStatusConstants.IO_EXCEPTION);
1190    }
1191}
1192/**
1193 * Returns <code>true</code> if an equivalent package fragment is included in the package
1194 * region. Package fragments are equivalent if they both have the same name.
1195 */

1196protected boolean packageRegionContainsSamePackageFragment(PackageFragment element) {
1197    IJavaElement[] pkgs = this.packageRegion.getElements();
1198    for (int i = 0; i < pkgs.length; i++) {
1199        PackageFragment pkg = (PackageFragment) pkgs[i];
1200        if (Util.equalArraysOrNull(pkg.names, element.names))
1201            return true;
1202    }
1203    return false;
1204}
1205
1206/**
1207 * @see ITypeHierarchy
1208 * TODO (jerome) should use a PerThreadObject to build the hierarchy instead of synchronizing
1209 * (see also isAffected(IJavaElementDelta))
1210 */

1211public synchronized void refresh(IProgressMonitor monitor) throws JavaModelException {
1212    try {
1213        this.progressMonitor = monitor;
1214        if (monitor != null) {
1215            monitor.beginTask(
1216                    this.focusType != null ?
1217                            Messages.bind(Messages.hierarchy_creatingOnType, this.focusType.getFullyQualifiedName()) :
1218                            Messages.hierarchy_creating,
1219                    100);
1220        }
1221        long start = -1;
1222        if (DEBUG) {
1223            start = System.currentTimeMillis();
1224            if (this.computeSubtypes) {
1225                System.out.println("CREATING TYPE HIERARCHY [" + Thread.currentThread() + "]"); //$NON-NLS-1$ //$NON-NLS-2$
1226
} else {
1227                System.out.println("CREATING SUPER TYPE HIERARCHY [" + Thread.currentThread() + "]"); //$NON-NLS-1$ //$NON-NLS-2$
1228
}
1229            if (this.focusType != null) {
1230                System.out.println(" on type " + ((JavaElement)this.focusType).toStringWithAncestors()); //$NON-NLS-1$
1231
}
1232        }
1233
1234        compute();
1235        initializeRegions();
1236        this.needsRefresh = false;
1237        this.changeCollector = null;
1238
1239        if (DEBUG) {
1240            if (this.computeSubtypes) {
1241                System.out.println("CREATED TYPE HIERARCHY in " + (System.currentTimeMillis() - start) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$
1242
} else {
1243                System.out.println("CREATED SUPER TYPE HIERARCHY in " + (System.currentTimeMillis() - start) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$
1244
}
1245            System.out.println(this.toString());
1246        }
1247    } catch (JavaModelException e) {
1248        throw e;
1249    } catch (CoreException e) {
1250        throw new JavaModelException(e);
1251    } finally {
1252        if (monitor != null) {
1253            monitor.done();
1254        }
1255        this.progressMonitor = null;
1256    }
1257}
1258
1259/**
1260 * @see ITypeHierarchy
1261 */

1262public synchronized void removeTypeHierarchyChangedListener(ITypeHierarchyChangedListener listener) {
1263    ArrayList JavaDoc listeners = this.changeListeners;
1264    if (listeners == null) {
1265        return;
1266    }
1267    listeners.remove(listener);
1268
1269    // deregister from JavaCore on last listener removed
1270
if (listeners.isEmpty()) {
1271        JavaCore.removeElementChangedListener(this);
1272    }
1273}
1274/**
1275 * @see ITypeHierarchy
1276 */

1277public void store(OutputStream JavaDoc output, IProgressMonitor monitor) throws JavaModelException {
1278    try {
1279        // compute types in hierarchy
1280
Hashtable JavaDoc hashtable = new Hashtable JavaDoc();
1281        Hashtable JavaDoc hashtable2 = new Hashtable JavaDoc();
1282        int count = 0;
1283        
1284        if(this.focusType != null) {
1285            Integer JavaDoc index = new Integer JavaDoc(count++);
1286            hashtable.put(this.focusType, index);
1287            hashtable2.put(index, this.focusType);
1288        }
1289        Object JavaDoc[] types = this.classToSuperclass.entrySet().toArray();
1290        for (int i = 0; i < types.length; i++) {
1291            Map.Entry JavaDoc entry = (Map.Entry JavaDoc) types[i];
1292            Object JavaDoc t = entry.getKey();
1293            if(hashtable.get(t) == null) {
1294                Integer JavaDoc index = new Integer JavaDoc(count++);
1295                hashtable.put(t, index);
1296                hashtable2.put(index, t);
1297            }
1298            Object JavaDoc superClass = entry.getValue();
1299            if(superClass != null && hashtable.get(superClass) == null) {
1300                Integer JavaDoc index = new Integer JavaDoc(count++);
1301                hashtable.put(superClass, index);
1302                hashtable2.put(index, superClass);
1303            }
1304        }
1305        types = this.typeToSuperInterfaces.entrySet().toArray();
1306        for (int i = 0; i < types.length; i++) {
1307            Map.Entry JavaDoc entry = (Map.Entry JavaDoc) types[i];
1308            Object JavaDoc t = entry.getKey();
1309            if(hashtable.get(t) == null) {
1310                Integer JavaDoc index = new Integer JavaDoc(count++);
1311                hashtable.put(t, index);
1312                hashtable2.put(index, t);
1313            }
1314            Object JavaDoc[] sp = (Object JavaDoc[]) entry.getValue();
1315            if(sp != null) {
1316                for (int j = 0; j < sp.length; j++) {
1317                    Object JavaDoc superInterface = sp[j];
1318                    if(sp[j] != null && hashtable.get(superInterface) == null) {
1319                        Integer JavaDoc index = new Integer JavaDoc(count++);
1320                        hashtable.put(superInterface, index);
1321                        hashtable2.put(index, superInterface);
1322                    }
1323                }
1324            }
1325        }
1326        // save version of the hierarchy format
1327
output.write(VERSION);
1328        
1329        // save general info
1330
byte generalInfo = 0;
1331        if(this.computeSubtypes) {
1332            generalInfo |= COMPUTE_SUBTYPES;
1333        }
1334        output.write(generalInfo);
1335        
1336        // save project
1337
if(this.project != null) {
1338            output.write(this.project.getHandleIdentifier().getBytes());
1339        }
1340        output.write(SEPARATOR1);
1341        
1342        // save missing types
1343
for (int i = 0; i < this.missingTypes.size(); i++) {
1344            if(i != 0) {
1345                output.write(SEPARATOR2);
1346            }
1347            output.write(((String JavaDoc)this.missingTypes.get(i)).getBytes());
1348            
1349        }
1350        output.write(SEPARATOR1);
1351        
1352        // save types
1353
for (int i = 0; i < count ; i++) {
1354            IType t = (IType)hashtable2.get(new Integer JavaDoc(i));
1355            
1356            // n bytes
1357
output.write(t.getHandleIdentifier().getBytes());
1358            output.write(SEPARATOR4);
1359            output.write(flagsToBytes((Integer JavaDoc)this.typeFlags.get(t)));
1360            output.write(SEPARATOR4);
1361            byte info = CLASS;
1362            if(this.focusType != null && this.focusType.equals(t)) {
1363                info |= COMPUTED_FOR;
1364            }
1365            if(this.interfaces.contains(t)) {
1366                info |= INTERFACE;
1367            }
1368            if(this.rootClasses.contains(t)) {
1369                info |= ROOT;
1370            }
1371            output.write(info);
1372        }
1373        output.write(SEPARATOR1);
1374        
1375        // save superclasses
1376
types = this.classToSuperclass.entrySet().toArray();
1377        for (int i = 0; i < types.length; i++) {
1378            Map.Entry JavaDoc entry = (Map.Entry JavaDoc) types[i];
1379            IJavaElement key = (IJavaElement) entry.getKey();
1380            IJavaElement value = (IJavaElement) entry.getValue();
1381            
1382            output.write(((Integer JavaDoc)hashtable.get(key)).toString().getBytes());
1383            output.write('>');
1384            output.write(((Integer JavaDoc)hashtable.get(value)).toString().getBytes());
1385            output.write(SEPARATOR1);
1386        }
1387        output.write(SEPARATOR1);
1388        
1389        // save superinterfaces
1390
types = this.typeToSuperInterfaces.entrySet().toArray();
1391        for (int i = 0; i < types.length; i++) {
1392            Map.Entry JavaDoc entry = (Map.Entry JavaDoc) types[i];
1393            IJavaElement key = (IJavaElement) entry.getKey();
1394            IJavaElement[] values = (IJavaElement[]) entry.getValue();
1395            
1396            if(values.length > 0) {
1397                output.write(((Integer JavaDoc)hashtable.get(key)).toString().getBytes());
1398                output.write(SEPARATOR3);
1399                for (int j = 0; j < values.length; j++) {
1400                    IJavaElement value = values[j];
1401                    if(j != 0) output.write(SEPARATOR2);
1402                    output.write(((Integer JavaDoc)hashtable.get(value)).toString().getBytes());
1403                }
1404                output.write(SEPARATOR1);
1405            }
1406        }
1407        output.write(SEPARATOR1);
1408    } catch(IOException JavaDoc e) {
1409        throw new JavaModelException(e, IJavaModelStatusConstants.IO_EXCEPTION);
1410    }
1411}
1412/**
1413 * Returns whether the simple name of a supertype of the given type is
1414 * the simple name of one of the subtypes in this hierarchy or the
1415 * simple name of this type.
1416 */

1417boolean subtypesIncludeSupertypeOf(IType type) {
1418    // look for superclass
1419
String JavaDoc superclassName = null;
1420    try {
1421        superclassName = type.getSuperclassName();
1422    } catch (JavaModelException e) {
1423        if (DEBUG) {
1424            e.printStackTrace();
1425        }
1426        return false;
1427    }
1428    if (superclassName == null) {
1429        superclassName = "Object"; //$NON-NLS-1$
1430
}
1431    int dot = -1;
1432    String JavaDoc simpleSuper = (dot = superclassName.lastIndexOf('.')) > -1 ?
1433        superclassName.substring(dot + 1) :
1434        superclassName;
1435    if (hasSubtypeNamed(simpleSuper)) {
1436        return true;
1437    }
1438
1439    // look for super interfaces
1440
String JavaDoc[] interfaceNames = null;
1441    try {
1442        interfaceNames = type.getSuperInterfaceNames();
1443    } catch (JavaModelException e) {
1444        if (DEBUG)
1445            e.printStackTrace();
1446        return false;
1447    }
1448    for (int i = 0, length = interfaceNames.length; i < length; i++) {
1449        dot = -1;
1450        String JavaDoc interfaceName = interfaceNames[i];
1451        String JavaDoc simpleInterface = (dot = interfaceName.lastIndexOf('.')) > -1 ?
1452            interfaceName.substring(dot) :
1453            interfaceName;
1454        if (hasSubtypeNamed(simpleInterface)) {
1455            return true;
1456        }
1457    }
1458    
1459    return false;
1460}
1461/**
1462 * @see ITypeHierarchy
1463 */

1464public String JavaDoc toString() {
1465    StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
1466    buffer.append("Focus: "); //$NON-NLS-1$
1467
buffer.append(this.focusType == null ? "<NONE>" : ((JavaElement)this.focusType).toStringWithAncestors(false/*don't show key*/)); //$NON-NLS-1$
1468
buffer.append("\n"); //$NON-NLS-1$
1469
if (exists()) {
1470        if (this.focusType != null) {
1471            buffer.append("Super types:\n"); //$NON-NLS-1$
1472
toString(buffer, this.focusType, 1, true);
1473            buffer.append("Sub types:\n"); //$NON-NLS-1$
1474
toString(buffer, this.focusType, 1, false);
1475        } else {
1476            buffer.append("Sub types of root classes:\n"); //$NON-NLS-1$
1477
IJavaElement[] roots = Util.sortCopy(getRootClasses());
1478            for (int i= 0; i < roots.length; i++) {
1479                toString(buffer, (IType) roots[i], 1, false);
1480            }
1481        }
1482        if (this.rootClasses.size > 1) {
1483            buffer.append("Root classes:\n"); //$NON-NLS-1$
1484
IJavaElement[] roots = Util.sortCopy(getRootClasses());
1485            for (int i = 0, length = roots.length; i < length; i++) {
1486                toString(buffer, (IType) roots[i], 1, false);
1487            }
1488        } else if (this.rootClasses.size == 0) {
1489            // see http://bugs.eclipse.org/bugs/show_bug.cgi?id=24691
1490
buffer.append("No root classes"); //$NON-NLS-1$
1491
}
1492    } else {
1493        buffer.append("(Hierarchy became stale)"); //$NON-NLS-1$
1494
}
1495    return buffer.toString();
1496}
1497/**
1498 * Append a String to the given buffer representing the hierarchy for the type,
1499 * beginning with the specified indentation level.
1500 * If ascendant, shows the super types, otherwise show the sub types.
1501 */

1502private void toString(StringBuffer JavaDoc buffer, IType type, int indent, boolean ascendant) {
1503    IType[] types= ascendant ? getSupertypes(type) : getSubtypes(type);
1504    IJavaElement[] sortedTypes = Util.sortCopy(types);
1505    for (int i= 0; i < sortedTypes.length; i++) {
1506        for (int j= 0; j < indent; j++) {
1507            buffer.append(" "); //$NON-NLS-1$
1508
}
1509        JavaElement element = (JavaElement)sortedTypes[i];
1510        buffer.append(element.toStringWithAncestors(false/*don't show key*/));
1511        buffer.append('\n');
1512        toString(buffer, types[i], indent + 1, ascendant);
1513    }
1514}
1515/**
1516 * Returns whether one of the types in this hierarchy has a supertype whose simple
1517 * name is the given simple name.
1518 */

1519boolean hasSupertype(String JavaDoc simpleName) {
1520    for(Iterator JavaDoc iter = this.classToSuperclass.values().iterator(); iter.hasNext();){
1521        IType superType = (IType)iter.next();
1522        if (superType.getElementName().equals(simpleName)) {
1523            return true;
1524        }
1525    }
1526    return false;
1527}
1528/**
1529 * @see IProgressMonitor
1530 */

1531protected void worked(int work) {
1532    if (this.progressMonitor != null) {
1533        this.progressMonitor.worked(work);
1534        checkCanceled();
1535    }
1536}
1537}
1538
Popular Tags