Index: browser/org/eclipse/cdt/core/browser/AllTypesCache.java
===================================================================
RCS file: /home/tools/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/AllTypesCache.java,v
retrieving revision 1.6
diff -u -r1.6 AllTypesCache.java
--- browser/org/eclipse/cdt/core/browser/AllTypesCache.java	26 May 2004 14:49:00 -0000	1.6
+++ browser/org/eclipse/cdt/core/browser/AllTypesCache.java	14 Jul 2004 19:47:17 -0000
@@ -14,6 +14,8 @@
 import java.util.Collection;
 
 import org.eclipse.cdt.core.CCorePlugin;
+import org.eclipse.cdt.core.browser.typehierarchy.ITypeHierarchy;
+import org.eclipse.cdt.core.browser.typehierarchy.TypeHierarchyBuilder;
 import org.eclipse.cdt.core.model.CModelException;
 import org.eclipse.cdt.core.model.CoreModel;
 import org.eclipse.cdt.core.model.ElementChangedEvent;
@@ -48,7 +50,7 @@
 
 	private static final int INITIAL_DELAY = 5000;
 	private static IWorkingCopyProvider fgWorkingCopyProvider;
-	private static TypeCacheManager fgTypeCacheManager;
+	private static TypeHierarchyBuilder fgTypeHierarchyBuilder;
 	private static IElementChangedListener fgElementChangedListener;
 	private static IPropertyChangeListener fgPropertyChangeListener;
 	private static boolean fgEnableIndexing = true;
@@ -63,7 +65,8 @@
 	 */
 	public static void initialize(IWorkingCopyProvider workingCopyProvider) {
 		fgWorkingCopyProvider = workingCopyProvider;
-		fgTypeCacheManager = new TypeCacheManager(fgWorkingCopyProvider);
+		TypeCacheManager.getInstance().setWorkingCopyProvider(fgWorkingCopyProvider);
+		fgTypeHierarchyBuilder = new TypeHierarchyBuilder();
 
 		// load prefs
 		Preferences prefs = CCorePlugin.getDefault().getPluginPreferences();
@@ -77,13 +80,13 @@
 		}
 		
 		// start jobs in background after INITIAL_DELAY
-		fgTypeCacheManager.reconcile(fgEnableIndexing, Job.BUILD, INITIAL_DELAY);
+		TypeCacheManager.getInstance().reconcile(fgEnableIndexing, Job.BUILD, INITIAL_DELAY);
 
 		// add delta listener
 		fgElementChangedListener = new IElementChangedListener() {
 			public void elementChanged(ElementChangedEvent event) {
-				fgTypeCacheManager.processDelta(event.getDelta());
-				fgTypeCacheManager.reconcile(fgEnableIndexing, Job.BUILD, 0);
+				TypeCacheManager.getInstance().processDelta(event.getDelta());
+				TypeCacheManager.getInstance().reconcile(fgEnableIndexing, Job.BUILD, 0);
 			}
 		};
 		CoreModel.getDefault().addElementChangedListener(fgElementChangedListener);
@@ -96,9 +99,9 @@
 					String value = (String) event.getNewValue();
 					fgEnableIndexing = Boolean.valueOf(value).booleanValue();
 					if (!fgEnableIndexing) {
-						fgTypeCacheManager.cancelJobs();
+						TypeCacheManager.getInstance().cancelJobs();
 					} else {
-						fgTypeCacheManager.reconcile(fgEnableIndexing, Job.BUILD, 0);
+						TypeCacheManager.getInstance().reconcile(fgEnableIndexing, Job.BUILD, 0);
 					}
 				}
 			}
@@ -119,8 +122,8 @@
 			CCorePlugin.getDefault().getPluginPreferences().removePropertyChangeListener(fgPropertyChangeListener);
 
 		// terminate all running jobs
-		if (fgTypeCacheManager != null) {
-			fgTypeCacheManager.cancelJobs();
+		if (TypeCacheManager.getInstance() != null) {
+			TypeCacheManager.getInstance().cancelJobs();
 		}
 	}
 	
@@ -139,7 +142,7 @@
 			public boolean shouldContinue() { return true; }
 		};
 		for (int i = 0; i < projects.length; ++i) {
-			fgTypeCacheManager.getCache(projects[i]).accept(visitor);
+			TypeCacheManager.getInstance().getCache(projects[i]).accept(visitor);
 		}
 		return (ITypeInfo[]) fAllTypes.toArray(new ITypeInfo[fAllTypes.size()]);
 	}
@@ -167,7 +170,7 @@
 			public boolean shouldContinue() { return true; }
 		};
 		for (int i = 0; i < projects.length; ++i) {
-			fgTypeCacheManager.getCache(projects[i]).accept(visitor);
+			TypeCacheManager.getInstance().getCache(projects[i]).accept(visitor);
 		}
 		return (ITypeInfo[]) fTypesFound.toArray(new ITypeInfo[fTypesFound.size()]);
 	}
@@ -198,7 +201,7 @@
 			public boolean shouldContinue() { return true; }
 		};
 		for (int i = 0; i < projects.length; ++i) {
-			fgTypeCacheManager.getCache(projects[i]).accept(visitor);
+			TypeCacheManager.getInstance().getCache(projects[i]).accept(visitor);
 		}
 		return (ITypeInfo[]) fTypesFound.toArray(new ITypeInfo[fTypesFound.size()]);
 	}
@@ -224,7 +227,7 @@
 			public boolean shouldContinue() { return true; }
 		};
 		for (int i = 0; i < projects.length; ++i) {
-			ITypeCache cache = fgTypeCacheManager.getCache(projects[i]);
+			ITypeCache cache = TypeCacheManager.getInstance().getCache(projects[i]);
 			cache.accept(visitor);
 			if (includeGlobalNamespace) {
 				fTypesFound.add(cache.getGlobalNamespace());
@@ -243,7 +246,7 @@
 		for (int i = 0; i < projects.length; ++i) {
 			IProject project = projects[i];
 			if (project.exists() && project.isOpen()) {
-				if (!fgTypeCacheManager.getCache(project).isUpToDate())
+				if (!TypeCacheManager.getInstance().getCache(project).isUpToDate())
 					return false;
 			}
 		}
@@ -277,7 +280,7 @@
 		for (int i = 0; i < projects.length; ++i) {
 			IProject project = projects[i];
 			// wait for any running jobs to finish
-			fgTypeCacheManager.getCache(project).reconcileAndWait(true, Job.SHORT, monitor);
+			TypeCacheManager.getInstance().getCache(project).reconcileAndWait(true, Job.SHORT, monitor);
 		}
 		monitor.done();
 	}
@@ -293,17 +296,36 @@
 		if (location == null) {
 			// cancel background jobs
 			IProject project = info.getEnclosingProject();
-			fgTypeCacheManager.getCache(project).cancelJobs();
+			TypeCacheManager.getInstance().getCache(project).cancelJobs();
 
 			// start the search job
-			fgTypeCacheManager.getCache(project).locateTypeAndWait(info, Job.SHORT, monitor);
+			TypeCacheManager.getInstance().getCache(project).locateTypeAndWait(info, Job.SHORT, monitor);
 
 			// get the newly parsed location
 			location = info.getResolvedReference();
 
 			// resume background jobs
-			fgTypeCacheManager.reconcile(fgEnableIndexing, Job.BUILD, 0);
+			TypeCacheManager.getInstance().reconcile(fgEnableIndexing, Job.BUILD, 0);
 		}
 		return location;
+	}
+	
+	public static ITypeInfo getTypeForElement(ICElement elem) {
+	    return TypeUtil.getTypeForElement(elem);
+	}
+
+	/**
+	 * Creates and returns a type hierarchy for this type containing
+	 * this type and all of its supertypes and subtypes in the workspace.
+	 *
+	 * @param info the given type
+	 * @param monitor the given progress monitor
+	 * @return a type hierarchy for the given type
+	 */
+	public static ITypeHierarchy createTypeHierarchy(ICElement type, IProgressMonitor monitor) throws CModelException {
+	    ITypeInfo info = TypeUtil.getTypeForElement(type);
+	    if (info != null)
+	        return fgTypeHierarchyBuilder.createTypeHierarchy(info, fgEnableIndexing, monitor);
+	    return null;
 	}
 }
Index: browser/org/eclipse/cdt/core/browser/ITypeInfo.java
===================================================================
RCS file: /home/tools/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/ITypeInfo.java,v
retrieving revision 1.5
diff -u -r1.5 ITypeInfo.java
--- browser/org/eclipse/cdt/core/browser/ITypeInfo.java	21 Jun 2004 18:48:03 -0000	1.5
+++ browser/org/eclipse/cdt/core/browser/ITypeInfo.java	14 Jul 2004 19:47:17 -0000
@@ -11,6 +11,7 @@
 package org.eclipse.cdt.core.browser;
 
 import org.eclipse.cdt.core.model.ICElement;
+import org.eclipse.cdt.core.parser.ast.ASTAccessVisibility;
 import org.eclipse.cdt.internal.core.browser.cache.ITypeCache;
 import org.eclipse.core.resources.IProject;
 
@@ -146,15 +147,58 @@
 	public ITypeReference getResolvedReference();
 	
 	/**
-	 * Returns the corresponding CElement or <code>null</code> if not found.
-	 */
-	public ICElement getCElement();
-	
-	/**
 	 * Returns true if the type can be substituted.
 	 */
 	public boolean canSubstituteFor(ITypeInfo info);
 
 	public ITypeCache getCache();
 	public void setCache(ITypeCache typeCache);
+	
+	/**
+	 * Returns true if other types extend this type.
+	 */
+	public boolean hasSubTypes();
+	
+	/** Gets all types which extend this type.
+	 * @return array of types, or <code>null</code> if none found.
+	 */
+	public ITypeInfo[] getSubTypes();
+	
+	/**
+	 * Returns true if this type has base classes.
+	 */
+	public boolean hasSuperTypes();
+	
+	/** Gets the base classes.
+	 * @return array of types, or <code>null</code> if none found.
+	 */
+	public ITypeInfo[] getSuperTypes();
+	
+	/**
+	 * Gets the base class access visibility (PRIVATE, PROTECTED, PUBLIC)
+	 */
+	public ASTAccessVisibility getSuperTypeAccess(ITypeInfo subType);
+
+	/**
+	 * Adds a derived class reference, i.e. this type is used as
+	 * a base class at the given location.
+	 */
+	public void addDerivedReference(ITypeReference location);
+
+	/** Gets the originating locations where this type was
+	 * used as a base class.
+	 * @return all known source references, or an empty
+	 * array if none found.
+	 */
+	public ITypeReference[] getDerivedReferences();
+	
+	/**
+	 * Returns true if the type is a class or struct.
+	 */
+	public boolean isClass();
+
+	/**
+	 * Returns true if type is referenced in the given scope.
+	 */
+	public boolean isReferenced(ITypeSearchScope scope);
 }
Index: browser/org/eclipse/cdt/core/browser/TypeInfo.java
===================================================================
RCS file: /home/tools/org.eclipse.cdt.core/browser/org/eclipse/cdt/core/browser/TypeInfo.java,v
retrieving revision 1.8
diff -u -r1.8 TypeInfo.java
--- browser/org/eclipse/cdt/core/browser/TypeInfo.java	6 Jul 2004 17:50:51 -0000	1.8
+++ browser/org/eclipse/cdt/core/browser/TypeInfo.java	14 Jul 2004 19:47:17 -0000
@@ -10,7 +10,10 @@
  *******************************************************************************/
 package org.eclipse.cdt.core.browser;
 
+import java.util.Iterator;
+
 import org.eclipse.cdt.core.model.ICElement;
+import org.eclipse.cdt.core.parser.ast.ASTAccessVisibility;
 import org.eclipse.cdt.internal.core.browser.cache.ITypeCache;
 import org.eclipse.cdt.internal.core.browser.util.ArrayUtil;
 import org.eclipse.core.resources.IProject;
@@ -22,6 +25,8 @@
 	protected IQualifiedTypeName fQualifiedName;
 	protected ITypeReference[] fSourceRefs = null;
 	protected int fSourceRefsCount = 0;
+	protected ITypeReference[] fDerivedSourceRefs = null;
+	protected int fDerivedSourceRefsCount = 0;
 
 	protected final static int INITIAL_REFS_SIZE = 1;
 	protected final static int REFS_GROW_BY = 2;
@@ -54,26 +59,6 @@
 		return null;
 	}
 	
-	public ICElement getCElement() {
-		ITypeReference ref = getResolvedReference();
-		if (ref != null) {
-			ICElement[] elems = ref.getCElements();
-			if (elems != null && elems.length > 0) {
-				if (elems.length == 1)
-					return elems[0];
-
-				for (int i = 0; i < elems.length; ++i) {
-					ICElement elem = elems[i];
-					if (elem.getElementType() == fElementType && elem.getElementName().equals(getName())) {
-						//TODO should check fully qualified name
-						return elem;
-					}
-				}
-			}
-		}
-		return null;
-	}
-
 	public ITypeReference getResolvedReference() {
 		for (int i = 0; i < fSourceRefsCount; ++i) {
 			ITypeReference location = fSourceRefs[i];
@@ -85,9 +70,28 @@
 	}
 
 	public boolean isReferenced() {
-		return (fSourceRefs != null);
+		return (fSourceRefs != null || fDerivedSourceRefs != null);
 	}
 	
+	public boolean isReferenced(ITypeSearchScope scope) {
+		if (scope == null || scope.isWorkspaceScope())
+			return true;
+
+		// check if path is in scope
+		for (int i = 0; i < fSourceRefsCount; ++i) {
+			ITypeReference location = fSourceRefs[i];
+			if (scope.encloses(location.getPath()))
+				return true;
+		}
+		for (int i = 0; i < fDerivedSourceRefsCount; ++i) {
+			ITypeReference location = fDerivedSourceRefs[i];
+			if (scope.encloses(location.getPath()))
+				return true;
+		}
+		
+		return false;
+	}
+
 	public boolean isUndefinedType() {
 		return fElementType == 0;
 	}
@@ -255,5 +259,65 @@
 
 	public void setCache(ITypeCache typeCache) {
 		fTypeCache = typeCache;
+	}
+	
+	public void addDerivedReference(ITypeReference location) {
+		if (fDerivedSourceRefs == null) {
+		    fDerivedSourceRefs = new ITypeReference[INITIAL_REFS_SIZE];
+		    fDerivedSourceRefsCount = 0;
+		} else if (fDerivedSourceRefsCount == fDerivedSourceRefs.length) {
+			ITypeReference[] refs = new ITypeReference[fDerivedSourceRefs.length + REFS_GROW_BY];
+			System.arraycopy(fDerivedSourceRefs, 0, refs, 0, fDerivedSourceRefsCount);
+			fDerivedSourceRefs = refs;
+		}
+		fDerivedSourceRefs[fDerivedSourceRefsCount] = location;
+		++fDerivedSourceRefsCount;
+	}
+	
+	public ITypeReference[] getDerivedReferences() {
+		if (fDerivedSourceRefs != null) {
+			ITypeReference[] refs = new ITypeReference[fDerivedSourceRefsCount];
+			System.arraycopy(fDerivedSourceRefs, 0, refs, 0, fDerivedSourceRefsCount);
+			return refs;
+		}
+		return null;
+	}
+	
+	public boolean hasSubTypes() {
+		return (fDerivedSourceRefs != null);
+	}
+	
+	public ITypeInfo[] getSubTypes() {
+		if (fTypeCache != null) {
+			return fTypeCache.getSubtypes(this);
+		}
+		return null;
+	}
+	
+	public boolean hasSuperTypes() {
+		if (fTypeCache != null) {
+			return (fTypeCache.getSupertypes(this) != null);
+		}
+		return false;
+//		return true;	//TODO can't know this until we parse
+	}
+	
+	public ITypeInfo[] getSuperTypes() {
+		if (fTypeCache != null) {
+			return fTypeCache.getSupertypes(this);
+		}
+		return null;
+	}
+
+	public ASTAccessVisibility getSuperTypeAccess(ITypeInfo superType) {
+		if (fTypeCache != null) {
+			return fTypeCache.getSupertypeAccess(this, superType);
+		}
+		return null;
+	}
+
+	public boolean isClass() {
+		return (fElementType == ICElement.C_CLASS
+				|| fElementType == ICElement.C_STRUCT);
 	}
 }
Index: browser/org/eclipse/cdt/internal/core/browser/cache/ITypeCache.java
===================================================================
RCS file: /home/tools/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/ITypeCache.java,v
retrieving revision 1.2
diff -u -r1.2 ITypeCache.java
--- browser/org/eclipse/cdt/internal/core/browser/cache/ITypeCache.java	26 May 2004 14:49:00 -0000	1.2
+++ browser/org/eclipse/cdt/internal/core/browser/cache/ITypeCache.java	14 Jul 2004 19:47:17 -0000
@@ -15,6 +15,7 @@
 import org.eclipse.cdt.core.browser.ITypeInfoVisitor;
 import org.eclipse.cdt.core.browser.ITypeReference;
 import org.eclipse.cdt.core.browser.ITypeSearchScope;
+import org.eclipse.cdt.core.parser.ast.ASTAccessVisibility;
 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.IProgressMonitor;
@@ -40,6 +41,22 @@
 	 */
 	public void insert(ITypeInfo info);
 
+	/** Adds subtype to type.
+	 * 
+	 * @param type
+	 * @param subtype
+	 */
+	public void addSubtype(ITypeInfo type, ITypeInfo subtype);
+
+	/** Adds supertype to type.
+	 * 
+	 * @param type the type
+	 * @param supertype the supertype
+	 * @param the access visibility (PUBLIC, PROTECTED, PRIVATE)
+	 * @param isVirtual <code>true</code> if virtual base class
+	 */
+	public void addSupertype(ITypeInfo type, ITypeInfo supertype, ASTAccessVisibility access, boolean isVirtual);
+
 	/** Removes type from cache.
 	 * 
 	 * @param info
@@ -134,6 +151,29 @@
 	 */
 	public ITypeInfo[] getEnclosedTypes(ITypeInfo info, int kinds[]);
 	
+	/** Returns all types in the cache are supertypes of the given type.
+	 * 
+	 * @param info the given type
+	 * @return Array of supertypes, or <code>null</code> if none found.
+	 */
+	public ITypeInfo[] getSupertypes(ITypeInfo info);
+	
+	/** Returns the supertype access visiblity.
+	 * 
+	 * @param type the given type
+	 * @param supertype the supertype
+	 * @return the visibility (PRIVATE, PROTECTED, PUBLIC) or <code>null</code> if none found.
+	 */
+	public ASTAccessVisibility getSupertypeAccess(ITypeInfo type, ITypeInfo superType);
+	
+
+	/** Returns all types in the cache which extend the given type.
+	 * 
+	 * @param info the given type
+	 * @return Array of subtypes, or <code>null</code> if none found.
+	 */
+	public ITypeInfo[] getSubtypes(ITypeInfo info);
+
 	/** Returns the project associated with this cache.
 	 * 
 	 * @return the project
@@ -154,5 +194,11 @@
 	public void locateType(ITypeInfo info, int priority, int delay);
 	public ITypeReference locateTypeAndWait(ITypeInfo info, int priority, IProgressMonitor monitor);
 	
+	public void locateSupertypes(ITypeInfo info, int priority, int delay);
+	public ITypeInfo[] locateSupertypesAndWait(ITypeInfo info, int priority, IProgressMonitor monitor);
+
+	public void locateSubtypes(ITypeInfo info, int priority, int delay);
+	public ITypeInfo[] locateSubtypesAndWait(ITypeInfo info, int priority, IProgressMonitor monitor);
+
 	public ITypeInfo getGlobalNamespace();
 }
Index: browser/org/eclipse/cdt/internal/core/browser/cache/IndexerTypesJob.java
===================================================================
RCS file: /home/tools/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/IndexerTypesJob.java,v
retrieving revision 1.3
diff -u -r1.3 IndexerTypesJob.java
--- browser/org/eclipse/cdt/internal/core/browser/cache/IndexerTypesJob.java	17 Jun 2004 19:20:08 -0000	1.3
+++ browser/org/eclipse/cdt/internal/core/browser/cache/IndexerTypesJob.java	14 Jul 2004 19:47:17 -0000
@@ -30,6 +30,7 @@
 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.Path;
 
 public class IndexerTypesJob extends IndexerJob {
 	
@@ -108,6 +109,14 @@
 						String[] enclosingNames = getEnclosingNames(word, slash);
 						addType(input, project, entry, type, name, enclosingNames, monitor);
 					}
+				} else if (decodedType == IIndexConstants.DERIVED_SUFFIX) {
+					firstSlash += 2;
+					int slash = CharOperation.indexOf(IIndexConstants.SEPARATOR, word, firstSlash + 1);
+					String name = String.valueOf(CharOperation.subarray(word, firstSlash + 1, slash));
+					if (name.length() != 0) {  // skip anonymous structs
+						String[] enclosingNames = getEnclosingNames(word, slash);
+						addSuperTypeReference(input, project, entry, name, enclosingNames, monitor);
+					}
 				}
 			}
 		}
@@ -171,6 +180,39 @@
 				if (file != null && file.getPath() != null) {
 					IPath path = PathUtil.getWorkspaceRelativePath(file.getPath());
 					info.addReference(new TypeReference(path, project));
+				}
+			}
+		}
+	}
+
+	private void addSuperTypeReference(IndexInput input, IProject project, IEntryResult entry, String name, String[] enclosingNames, IProgressMonitor monitor) throws InterruptedException, IOException {
+		QualifiedTypeName qualifiedName = new QualifiedTypeName(name, enclosingNames);
+		ITypeInfo info = fTypeCache.getType(ICElement.C_CLASS, qualifiedName);
+		if (info == null)
+			info = fTypeCache.getType(ICElement.C_STRUCT, qualifiedName);
+		if (info == null) {
+			// add dummy type to cache
+			info = new TypeInfo(0, qualifiedName);
+			fTypeCache.insert(info);
+		}
+		int[] references = entry.getFileReferences();
+		if (references != null && references.length > 0) {
+			for (int i = 0; i < references.length; ++i) {
+				if (monitor.isCanceled())
+					throw new InterruptedException();
+
+				IndexedFile file = input.getIndexedFile(references[i]);
+				if (file != null && file.getPath() != null) {
+					IPath path = PathUtil.getWorkspaceRelativePath(file.getPath());
+					info.addDerivedReference(new TypeReference(path, project));
+//
+//					// get absolute path
+//					IPath path = new Path(file.getPath());
+//					IPath projectPath = project.getFullPath();
+//					if (projectPath.isPrefixOf(path)) {
+//						path = project.getLocation().append(path.removeFirstSegments(projectPath.segmentCount()));
+//					}
+//					info.addDerivedReference(new TypeReference(path, project));
 				}
 			}
 		}
Index: browser/org/eclipse/cdt/internal/core/browser/cache/TypeCache.java
===================================================================
RCS file: /home/tools/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCache.java,v
retrieving revision 1.4
diff -u -r1.4 TypeCache.java
--- browser/org/eclipse/cdt/internal/core/browser/cache/TypeCache.java	17 Jun 2004 19:20:08 -0000	1.4
+++ browser/org/eclipse/cdt/internal/core/browser/cache/TypeCache.java	14 Jul 2004 19:47:17 -0000
@@ -28,6 +28,7 @@
 import org.eclipse.cdt.core.browser.TypeInfo;
 import org.eclipse.cdt.core.browser.TypeSearchScope;
 import org.eclipse.cdt.core.model.ICElement;
+import org.eclipse.cdt.core.parser.ast.ASTAccessVisibility;
 import org.eclipse.cdt.internal.core.browser.util.ArrayUtil;
 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.runtime.IPath;
@@ -49,6 +50,29 @@
 	private final IWorkingCopyProvider fWorkingCopyProvider;
 	private final Collection fDeltas = new ArrayList();
 	private final ITypeInfo fGlobalNamespace;
+	private final Map fTypeToSubTypes = new HashMap();
+	private final Map fTypeToSuperTypes = new HashMap();
+
+	private static final class SuperTypeEntry {
+		ITypeInfo superType;
+		ASTAccessVisibility access;
+		boolean isVirtual;
+		SuperTypeEntry(ITypeInfo superType, ASTAccessVisibility access, boolean isVirtual) {
+			this.superType = superType;
+			this.access = access;
+			this.isVirtual = isVirtual;
+		}
+	}
+	
+	private SuperTypeEntry findSuperTypeEntry(Collection entryCollection, ITypeInfo superType) {
+		for (Iterator i = entryCollection.iterator(); i.hasNext(); ) {
+			SuperTypeEntry e = (SuperTypeEntry) i.next();
+			if (e.superType.equals(superType)) {
+				return e;
+			}
+		}
+		return null;
+	}
 	
 	private static final int[] ENCLOSING_TYPES = {ICElement.C_NAMESPACE, ICElement.C_CLASS, ICElement.C_STRUCT, 0};
 	
@@ -330,6 +354,62 @@
 		fTypeKeyMap.clear();
 	}
 
+	public synchronized void addSupertype(ITypeInfo type, ITypeInfo supertype, ASTAccessVisibility access, boolean isVirtual) {
+		Collection entryCollection = (Collection) fTypeToSuperTypes.get(type);
+		if (entryCollection == null) {
+			entryCollection = new ArrayList();
+			fTypeToSuperTypes.put(type, entryCollection);
+		}
+		if (findSuperTypeEntry(entryCollection, supertype) == null) {
+			entryCollection.add(new SuperTypeEntry(supertype, access, isVirtual));
+			supertype.setCache(this);
+		}
+	}
+
+	public synchronized ITypeInfo[] getSupertypes(ITypeInfo type) {
+		Collection entryCollection = (Collection) fTypeToSuperTypes.get(type);
+		if (entryCollection != null && !entryCollection.isEmpty()) {
+			ITypeInfo[] superTypes = new ITypeInfo[entryCollection.size()];
+			int count = 0;
+			for (Iterator i = entryCollection.iterator(); i.hasNext(); ) {
+				SuperTypeEntry e = (SuperTypeEntry) i.next();
+				superTypes[count++] = e.superType;
+			}
+			return superTypes;
+		}
+		return null;
+	}
+
+	public ASTAccessVisibility getSupertypeAccess(ITypeInfo type, ITypeInfo superType) {
+		Collection entryCollection = (Collection) fTypeToSuperTypes.get(type);
+		if (entryCollection != null && !entryCollection.isEmpty()) {
+			SuperTypeEntry e = findSuperTypeEntry(entryCollection, superType);
+			if (e != null)
+				return e.access;
+		}
+		return null;
+	}
+	
+	public synchronized void addSubtype(ITypeInfo type, ITypeInfo subtype) {
+		Collection typeCollection = (Collection) fTypeToSubTypes.get(type);
+		if (typeCollection == null) {
+			typeCollection = new ArrayList();
+			fTypeToSubTypes.put(type, typeCollection);
+		}
+		if (!typeCollection.contains(subtype)) {
+			typeCollection.add(subtype);
+			subtype.setCache(this);
+		}
+	}
+	
+	public synchronized ITypeInfo[] getSubtypes(ITypeInfo type) {
+		Collection typeCollection = (Collection) fTypeToSubTypes.get(type);
+		if (typeCollection != null && !typeCollection.isEmpty()) {
+			return (ITypeInfo[]) typeCollection.toArray(new ITypeInfo[typeCollection.size()]);
+		}
+		return null;
+	}
+
 	public synchronized void accept(ITypeInfoVisitor visitor) {
 		for (Iterator mapIter = fTypeKeyMap.entrySet().iterator(); mapIter.hasNext(); ) {
 			Map.Entry entry = (Map.Entry) mapIter.next();
@@ -579,6 +659,13 @@
 				locatorJob.cancel();
 			}
 		}
+		jobs = jobManager.find(SubTypeLocatorJob.FAMILY);
+		for (int i = 0; i < jobs.length; ++i) {
+			SubTypeLocatorJob locatorJob = (SubTypeLocatorJob) jobs[i];
+			if (locatorJob.getType().getEnclosingProject().equals(fProject)) {
+				locatorJob.cancel();
+			}
+		}
 	}
 	
 	public void locateType(ITypeInfo info, int priority, int delay) {
@@ -625,5 +712,78 @@
 		}
 		
 		return info.getResolvedReference();
+	}
+	
+	public void locateSupertypes(ITypeInfo info, int priority, int delay) {
+		ITypeInfo[] superTypes = getSupertypes(info);
+		if (superTypes != null)
+			return;	// nothing to do
+		
+		locateType(info, priority, delay);
+	}
+
+	public ITypeInfo[] locateSupertypesAndWait(ITypeInfo info, int priority, IProgressMonitor monitor) {
+		locateSupertypes(info, priority, 0);
+
+		// wait for jobs to complete
+		IJobManager jobManager = Platform.getJobManager();
+		Job[] jobs = jobManager.find(SubTypeLocatorJob.FAMILY);
+		for (int i = 0; i < jobs.length; ++i) {
+			SubTypeLocatorJob locatorJob = (SubTypeLocatorJob) jobs[i];
+			if (locatorJob.getType().equals(info)) {
+				try {
+					locatorJob.join(monitor);
+				} catch (InterruptedException e) {
+				}
+			}
+		}
+		
+		return getSupertypes(info);
+	}
+
+	public void locateSubtypes(ITypeInfo info, int priority, int delay) {
+		ITypeInfo[] subTypes = getSubtypes(info);
+		if (subTypes != null)
+			return;	// nothing to do
+
+		// cancel any scheduled or running jobs for this type
+		IJobManager jobManager = Platform.getJobManager();
+		Job[] jobs = jobManager.find(SubTypeLocatorJob.FAMILY);
+		for (int i = 0; i < jobs.length; ++i) {
+			SubTypeLocatorJob locatorJob = (SubTypeLocatorJob) jobs[i];
+			if (locatorJob.getType().equals(info)) {
+				locatorJob.cancel();
+			}
+		}
+		
+		// check again, in case some jobs finished in the meantime
+		subTypes = getSubtypes(info);
+		if (subTypes != null)
+			return;	// nothing to do
+		
+		// create a new job
+		SubTypeLocatorJob locatorJob = new SubTypeLocatorJob(info, this, fWorkingCopyProvider);
+		// schedule the new job
+		locatorJob.setPriority(priority);
+		locatorJob.schedule(delay);
+	}
+
+	public ITypeInfo[] locateSubtypesAndWait(ITypeInfo info, int priority, IProgressMonitor monitor) {
+		locateSubtypes(info, priority, 0);
+
+		// wait for jobs to complete
+		IJobManager jobManager = Platform.getJobManager();
+		Job[] jobs = jobManager.find(SubTypeLocatorJob.FAMILY);
+		for (int i = 0; i < jobs.length; ++i) {
+			SubTypeLocatorJob locatorJob = (SubTypeLocatorJob) jobs[i];
+			if (locatorJob.getType().equals(info)) {
+				try {
+					locatorJob.join(monitor);
+				} catch (InterruptedException e) {
+				}
+			}
+		}
+		
+		return getSubtypes(info);
 	}
 }
Index: browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacheManager.java
===================================================================
RCS file: /home/tools/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacheManager.java,v
retrieving revision 1.1
diff -u -r1.1 TypeCacheManager.java
--- browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacheManager.java	17 May 2004 15:48:48 -0000	1.1
+++ browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacheManager.java	14 Jul 2004 19:47:17 -0000
@@ -13,7 +13,10 @@
 import java.util.HashMap;
 import java.util.Map;
 
+import org.eclipse.cdt.core.browser.IQualifiedTypeName;
+import org.eclipse.cdt.core.browser.ITypeInfo;
 import org.eclipse.cdt.core.browser.IWorkingCopyProvider;
+import org.eclipse.cdt.core.browser.QualifiedTypeName;
 import org.eclipse.cdt.core.browser.TypeSearchScope;
 import org.eclipse.cdt.core.model.ICElement;
 import org.eclipse.cdt.core.model.ICElementDelta;
@@ -23,16 +26,26 @@
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.Platform;
 import org.eclipse.core.runtime.jobs.IJobManager;
+import org.eclipse.core.runtime.jobs.Job;
 
 public class TypeCacheManager {
 	
-	private Map fCacheMap = new HashMap();
+	private static final TypeCacheManager fgInstance = new TypeCacheManager();
+	private Map fCacheMap;
 	private IWorkingCopyProvider fWorkingCopyProvider;
 
-	public TypeCacheManager(IWorkingCopyProvider workingCopyProvider) {
-		fWorkingCopyProvider = workingCopyProvider;
+	private TypeCacheManager() {
+		fCacheMap = new HashMap();
+	}
+	
+	public static TypeCacheManager getInstance() {
+		return fgInstance;
 	}
 	
+	public void setWorkingCopyProvider(IWorkingCopyProvider workingCopyProvider) {
+		fWorkingCopyProvider = workingCopyProvider;
+	}
+
 	public synchronized void updateProject(IProject project) {
 		TypeCacheDelta cacheDelta = new TypeCacheDelta(project);
 		getCache(project).addDelta(cacheDelta);
@@ -193,5 +206,41 @@
 		IJobManager jobManager = Platform.getJobManager();
 		jobManager.cancel(TypeCacherJob.FAMILY);
 		jobManager.cancel(TypeLocatorJob.FAMILY);
+	}
+	
+	public ITypeInfo[] locateSuperTypesAndWait(ITypeInfo info, boolean enableIndexing, int priority, IProgressMonitor monitor) {
+		ITypeInfo[] superTypes = info.getSuperTypes();
+		if (superTypes == null) {
+			// cancel background jobs
+			IProject project = info.getEnclosingProject();
+			getCache(project).cancelJobs();
+
+			// start the search job
+			getCache(project).locateSupertypesAndWait(info, priority, monitor);
+			
+			superTypes = info.getSuperTypes();
+
+			// resume background jobs
+			reconcile(enableIndexing, Job.BUILD, 0);
+		}
+		return superTypes;
+	}
+
+	public ITypeInfo[] locateSubTypesAndWait(ITypeInfo info, boolean enableIndexing, int priority, IProgressMonitor monitor) {
+		ITypeInfo[] subTypes = info.getSubTypes();
+		if (subTypes == null) {
+			// cancel background jobs
+			IProject project = info.getEnclosingProject();
+			getCache(project).cancelJobs();
+
+			// start the search job
+			getCache(project).locateSubtypesAndWait(info, priority, monitor);
+			
+			subTypes = info.getSubTypes();
+
+			// resume background jobs
+			reconcile(enableIndexing, Job.BUILD, 0);
+		}
+		return subTypes;
 	}
 }
Index: browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacheMessages.properties
===================================================================
RCS file: /home/tools/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacheMessages.properties,v
retrieving revision 1.4
diff -u -r1.4 TypeCacheMessages.properties
--- browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacheMessages.properties	25 Jun 2004 13:29:03 -0000	1.4
+++ browser/org/eclipse/cdt/internal/core/browser/cache/TypeCacheMessages.properties	14 Jul 2004 19:47:17 -0000
@@ -17,5 +17,7 @@
 
 TypeLocatorJob.jobName=Type Locator
 TypeLocatorJob.taskName=Searching for Type Declaration...
+SubTypeLocatorJob.jobName=Subtype Locator
+SubTypeLocatorJob.taskName=Searching for Subtypes...
 
 TypeCache.globalNamespace=(global)
Index: browser/org/eclipse/cdt/internal/core/browser/cache/TypeParser.java
===================================================================
RCS file: /home/tools/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/cache/TypeParser.java,v
retrieving revision 1.7
diff -u -r1.7 TypeParser.java
--- browser/org/eclipse/cdt/internal/core/browser/cache/TypeParser.java	23 Jun 2004 03:32:16 -0000	1.7
+++ browser/org/eclipse/cdt/internal/core/browser/cache/TypeParser.java	14 Jul 2004 19:47:17 -0000
@@ -18,6 +18,7 @@
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Map;
+import java.util.Set;
 
 import org.eclipse.cdt.core.CCorePlugin;
 import org.eclipse.cdt.core.browser.ITypeInfo;
@@ -49,7 +50,12 @@
 import org.eclipse.cdt.core.parser.ParserMode;
 import org.eclipse.cdt.core.parser.ParserUtil;
 import org.eclipse.cdt.core.parser.ScannerInfo;
+import org.eclipse.cdt.core.parser.ast.ASTAccessVisibility;
 import org.eclipse.cdt.core.parser.ast.ASTClassKind;
+import org.eclipse.cdt.core.parser.ast.ASTNotImplementedException;
+import org.eclipse.cdt.core.parser.ast.IASTBaseSpecifier;
+import org.eclipse.cdt.core.parser.ast.IASTTypeSpecifier;
+import org.eclipse.cdt.core.parser.ast.IASTTypedefDeclaration;
 import org.eclipse.cdt.core.parser.ast.IASTASMDefinition;
 import org.eclipse.cdt.core.parser.ast.IASTAbstractTypeSpecifierDeclaration;
 import org.eclipse.cdt.core.parser.ast.IASTClassReference;
@@ -113,6 +119,8 @@
 	private final SimpleStack fScopeStack = new SimpleStack();
 	private final SimpleStack fResourceStack = new SimpleStack();
 	private ITypeInfo fTypeToFind;
+	private ITypeInfo fSuperTypeToFind;
+	private Set fProcessedTypes = new HashSet();
 	private boolean fFoundType;
 
 	public TypeParser(ITypeCache typeCache, IWorkingCopyProvider provider) {
@@ -247,6 +255,75 @@
 		return false;
 	}
 
+	public boolean findSubTypes(ITypeInfo info, IProgressMonitor monitor) throws InterruptedException {
+		if (monitor == null)
+			monitor = new NullProgressMonitor();
+
+		if (monitor.isCanceled())
+			throw new InterruptedException();
+		
+		fScope = new TypeSearchScope();
+		ITypeReference[] refs = info.getDerivedReferences();
+		if (refs == null || refs.length == 0)
+			return false;	// no source references
+		
+		for (int i = 0; i < refs.length; ++i) {
+			ITypeReference location = refs[i];
+			IPath path = location.getPath();
+			fScope.add(path, false, null);
+		}
+
+		Map workingCopyMap = null;
+		if (fWorkingCopyProvider != null) {
+			IWorkingCopy[] workingCopies = fWorkingCopyProvider.getWorkingCopies();
+			if (workingCopies != null && workingCopies.length > 0) {
+				workingCopyMap = new HashMap(workingCopies.length);
+				for (int i = 0; i < workingCopies.length; ++i) {
+					IWorkingCopy workingCopy = workingCopies[i];
+					IPath wcPath = workingCopy.getOriginalElement().getPath();
+					if (fScope.encloses(wcPath)) {
+//						// always flush working copies from cache?
+//						fTypeCache.flush(wcPath);
+						fScope.add(wcPath, false, null);
+						workingCopyMap.put(wcPath, workingCopy);
+					}
+				}
+			}
+		}
+		
+		fProject = fTypeCache.getProject();
+		IPath[] searchPaths = fTypeCache.getPaths(fScope);
+		Collection workingCopyPaths = new HashSet();
+		if (workingCopyMap != null) {
+			collectWorkingCopiesInProject(workingCopyMap, fProject, workingCopyPaths);
+			//TODO what about working copies outside the workspace?
+		}
+		
+		monitor.beginTask("", searchPaths.length + workingCopyPaths.size()); //$NON-NLS-1$
+		try {
+			fTypeToFind = null;
+			fSuperTypeToFind = info;
+			fFoundType = false;
+			for (Iterator pathIter = workingCopyPaths.iterator(); pathIter.hasNext(); ) {
+				IPath path = (IPath) pathIter.next();
+				parseSource(path, fProject, workingCopyMap, new SubProgressMonitor(monitor, 1));
+			}
+			for (int i = 0; i < searchPaths.length; ++i) {
+				IPath path = searchPaths[i];
+				if (!workingCopyPaths.contains(path)) {
+					parseSource(path, fProject, workingCopyMap, new SubProgressMonitor(monitor, 1));
+				} else {
+					monitor.worked(1);
+				}
+			}
+		} finally {
+			fTypeToFind = null;
+			fFoundType = false;
+			monitor.done();
+		}
+		return false;
+	}
+
 	private void collectWorkingCopiesInProject(Map workingCopyMap, IProject project, Collection workingCopyPaths) {
 		for (Iterator mapIter = workingCopyMap.entrySet().iterator(); mapIter.hasNext(); ) {
 			Map.Entry entry = (Map.Entry) mapIter.next();
@@ -582,6 +659,88 @@
 			throw new OperationCanceledException();
 		fResourceStack.pop();
 	}
+	
+	private String[] getEnclosingNames(IASTOffsetableNamedElement elem) {
+		String[] enclosingNames = null;
+		if (elem instanceof IASTQualifiedNameElement) {
+			String[] names = ((IASTQualifiedNameElement) elem).getFullyQualifiedName();
+			if (names != null && names.length > 1) {
+				enclosingNames = new String[names.length - 1];
+				System.arraycopy(names, 0, enclosingNames, 0, names.length - 1);
+			}
+		}
+		return enclosingNames;
+	}
+
+
+	private class NodeTypeInfo {
+		int type;
+		String name;
+		String[] enclosingNames;
+		int offset;
+		int end;
+		IASTOffsetableNamedElement offsetable;
+		
+		void init() {
+			type = 0;
+			name = null;
+			enclosingNames = null;
+			offset = 0;
+			end = 0;
+			offsetable = null;
+		}
+		
+		boolean parseNodeForTypeInfo(ISourceElementCallbackDelegate node) {
+			init();
+			
+			if (node instanceof IASTReference) {
+				IASTReference reference = (IASTReference) node;
+				offset = reference.getOffset();
+				end = offset + reference.getName().length();
+			} else if (node instanceof IASTOffsetableNamedElement) {
+				offsetable = (IASTOffsetableNamedElement) node;
+				offset = offsetable.getNameOffset() != 0 ? offsetable.getNameOffset() : offsetable.getStartingOffset();
+				end = offsetable.getNameEndOffset();
+				if (end == 0) {
+					end = offset + offsetable.getName().length();
+				}
+			}
+			
+			if (node instanceof IASTReference)
+				node = fLastDeclaration;
+			if (node instanceof IASTReference) {
+				offsetable = (IASTOffsetableNamedElement) ((IASTReference) node).getReferencedElement();
+				name = ((IASTReference) node).getName();
+			} else if (node instanceof IASTOffsetableNamedElement) {
+				offsetable = (IASTOffsetableNamedElement) node;
+				name = offsetable.getName();
+			} else {
+				return false;
+			}
+			
+			// skip unnamed structs
+			if (name == null || name.length() == 0)
+				return false;
+
+			// skip unused types
+			type = getElementType(offsetable);
+			if (type == 0) {
+				return false;
+			}
+			
+			// collect enclosing names
+			if (offsetable instanceof IASTQualifiedNameElement) {
+				String[] names = ((IASTQualifiedNameElement) offsetable).getFullyQualifiedName();
+				if (names != null && names.length > 1) {
+					enclosingNames = new String[names.length - 1];
+					System.arraycopy(names, 0, enclosingNames, 0, names.length - 1);
+				}
+			}
+			
+			return true;
+		}
+
+	}
 
 	private void acceptType(ISourceElementCallbackDelegate node) {
 		if (fProgressMonitor.isCanceled())
@@ -592,77 +751,59 @@
 		if (currentScope instanceof IASTFunction || currentScope instanceof IASTMethod) {
 			return;
 		}
-
-		int offset = 0;
-		int end = 0;
-		IASTOffsetableNamedElement offsetable = null;
-		String name = null;
-		int type = 0;
-		
-		if (node instanceof IASTReference) {
-			IASTReference reference = (IASTReference) node;
-			offset = reference.getOffset();
-			end = offset + reference.getName().length();
-		} else if (node instanceof IASTOffsetableNamedElement) {
-			offsetable = (IASTOffsetableNamedElement) node;
-			offset = offsetable.getNameOffset() != 0 ? offsetable.getNameOffset() : offsetable.getStartingOffset();
-			end = offsetable.getNameEndOffset();
-			if (end == 0) {
-				end = offset + offsetable.getName().length();
-			}
-		}
-		
-		if (node instanceof IASTReference)
-			node = fLastDeclaration;
-		if (node instanceof IASTReference) {
-			offsetable = (IASTOffsetableNamedElement) ((IASTReference) node).getReferencedElement();
-			name = ((IASTReference) node).getName();
-		} else if (node instanceof IASTOffsetableNamedElement) {
-			offsetable = (IASTOffsetableNamedElement) node;
-			name = offsetable.getName();
-		} else {
-			return;
-		}
 		
-		// skip unnamed structs
-		if (name == null || name.length() == 0)
-			return;
-
-		// skip unused types
-		type = getElementType(offsetable);
-		if (type == 0) {
-			return;
-		}
-		
-		if (fTypeToFind != null) {
-			if ((fTypeToFind.getCElementType() == type || fTypeToFind.isUndefinedType()) && name.equals(fTypeToFind.getName())) {
-				String[] enclosingNames = getEnclosingNames(offsetable);
-				QualifiedTypeName qualifiedName = new QualifiedTypeName(name, enclosingNames);
-				if (qualifiedName.equals(fTypeToFind.getQualifiedTypeName())) {
-					fFoundType = true;
-
-					// add types to cache
-					addType(type, name, enclosingNames, fResourceStack.bottom(), fResourceStack.top(), offset, end - offset);
-					fProgressMonitor.worked(1);
-				}
-			}
-		} else {
-			// add types to cache
-			addType(type, name, getEnclosingNames(offsetable), fResourceStack.bottom(), fResourceStack.top(), offset, end - offset);
-			fProgressMonitor.worked(1);
-		}
-	}
-	
-	private String[] getEnclosingNames(IASTOffsetableNamedElement elem) {
-		String[] enclosingNames = null;
-		if (elem instanceof IASTQualifiedNameElement) {
-			String[] names = ((IASTQualifiedNameElement) elem).getFullyQualifiedName();
-			if (names != null && names.length > 1) {
-				enclosingNames = new String[names.length - 1];
-				System.arraycopy(names, 0, enclosingNames, 0, names.length - 1);
+		NodeTypeInfo nodeInfo = new NodeTypeInfo();
+		if (nodeInfo.parseNodeForTypeInfo(node)) {
+			TypeReference originalLocation = null;
+			Object originalRef = fResourceStack.bottom();
+			if (originalRef instanceof IWorkingCopy) {
+				IWorkingCopy workingCopy = (IWorkingCopy) originalRef;
+				originalLocation = new TypeReference(workingCopy, fProject);
+			} else if (originalRef instanceof IResource) {
+				IResource resource = (IResource) originalRef;
+				originalLocation = new TypeReference(resource, fProject);
+			} else if (originalRef instanceof IPath) {
+				IPath path = PathUtil.getProjectRelativePath((IPath)originalRef, fProject);
+				originalLocation = new TypeReference(path, fProject);
+			}
+			
+			TypeReference resolvedLocation = null;
+			Object resolvedRef = fResourceStack.top();
+			if (resolvedRef instanceof IWorkingCopy) {
+				IWorkingCopy workingCopy = (IWorkingCopy) resolvedRef;
+				resolvedLocation = new TypeReference(workingCopy, fProject, nodeInfo.offset, nodeInfo.end - nodeInfo.offset);
+			} else if (resolvedRef instanceof IResource) {
+				IResource resource = (IResource) resolvedRef;
+				resolvedLocation = new TypeReference(resource, fProject, nodeInfo.offset, nodeInfo.end - nodeInfo.offset);
+			} else if (resolvedRef instanceof IPath) {
+				IPath path = PathUtil.getProjectRelativePath((IPath)resolvedRef, fProject);
+				resolvedLocation = new TypeReference(path, fProject, nodeInfo.offset, nodeInfo.end - nodeInfo.offset);
+			}
+			
+			if (fTypeToFind != null) {
+				if ((fTypeToFind.getCElementType() == nodeInfo.type || fTypeToFind.isUndefinedType()) && nodeInfo.name.equals(fTypeToFind.getName())) {
+					QualifiedTypeName qualifiedName = new QualifiedTypeName(nodeInfo.name, nodeInfo.enclosingNames);
+					if (qualifiedName.equals(fTypeToFind.getQualifiedTypeName())) {
+						fFoundType = true;
+
+						// add types to cache
+						ITypeInfo newType = addType(nodeInfo.type, qualifiedName, originalLocation, resolvedLocation);
+						if (newType != null && node instanceof IASTClassSpecifier) {
+							addSuperClasses(newType, (IASTClassSpecifier)node, originalLocation, fProcessedTypes);
+						}
+						fProgressMonitor.worked(1);
+					}
+				}
+			} else {
+				// add types to cache
+				QualifiedTypeName qualifiedName = new QualifiedTypeName(nodeInfo.name, nodeInfo.enclosingNames);
+				ITypeInfo newType = addType(nodeInfo.type, qualifiedName, originalLocation, resolvedLocation);
+				if (newType != null && node instanceof IASTClassSpecifier) {
+					addSuperClasses(newType, (IASTClassSpecifier)node, originalLocation, fProcessedTypes);
+				}
+				fProgressMonitor.worked(1);
 			}
 		}
-		return enclosingNames;
 	}
 
 	private int getElementType(IASTOffsetableNamedElement offsetable) {
@@ -690,8 +831,40 @@
 		return 0;
 	}
 	
-	private void addType(int type, String name, String[] enclosingNames, Object originalRef, Object resolvedRef, int offset, int length) {
-		QualifiedTypeName qualifiedName = new QualifiedTypeName(name, enclosingNames);
+	private void addSuperClasses(ITypeInfo type, IASTClassSpecifier classSpec, TypeReference location, Set processedClasses) {
+		Iterator baseIter = classSpec.getBaseClauses();
+		if (baseIter != null) {
+			while (baseIter.hasNext()) {
+				IASTBaseSpecifier baseSpec = (IASTBaseSpecifier) baseIter.next();
+				try {
+					String baseName = baseSpec.getParentClassName();
+					ASTAccessVisibility baseAccess = baseSpec.getAccess();
+					
+					IASTClassSpecifier parentClass = null;
+					IASTTypeSpecifier parentSpec = baseSpec.getParentClassSpecifier();
+					if (parentSpec instanceof IASTClassSpecifier)
+						parentClass = (IASTClassSpecifier) parentSpec;
+					
+					if (parentClass != null) {
+						NodeTypeInfo nodeInfo = new NodeTypeInfo();
+						if (nodeInfo.parseNodeForTypeInfo(parentClass)) {
+							// add type to cache
+							ITypeInfo superType = addSuperType(type, nodeInfo.type, nodeInfo.name, nodeInfo.enclosingNames, location, baseAccess, baseSpec.isVirtual());
+
+							// recursively process super super classes
+							if (!processedClasses.contains(parentClass)) {
+								processedClasses.add(parentClass);
+								addSuperClasses(superType, parentClass, location, processedClasses);
+							}
+						}
+					}
+				} catch (ASTNotImplementedException e) {
+				}
+			}
+		}
+	}
+
+	private ITypeInfo addType(int type, QualifiedTypeName qualifiedName, TypeReference originalLocation, TypeReference resolvedLocation) {
 		ITypeInfo info = fTypeCache.getType(type, qualifiedName);
 		if (info == null || info.isUndefinedType()) {
 			// add new type to cache
@@ -702,32 +875,35 @@
 				fTypeCache.insert(info);
 			}
 			
-			TypeReference location;
-			if (originalRef instanceof IWorkingCopy) {
-				IWorkingCopy workingCopy = (IWorkingCopy) originalRef;
-				location = new TypeReference(workingCopy, fProject);
-			} else if (originalRef instanceof IResource) {
-				IResource resource = (IResource) originalRef;
-				location = new TypeReference(resource, fProject);
+			info.addReference(originalLocation);
+		}
+		
+		info.addReference(resolvedLocation);
+		
+		return info;
+	}
+
+	private ITypeInfo addSuperType(ITypeInfo addToType, int type, String name, String[] enclosingNames, TypeReference location, ASTAccessVisibility access, boolean isVirtual) {
+		QualifiedTypeName qualifiedName = new QualifiedTypeName(name, enclosingNames);
+		ITypeInfo superType = fTypeCache.getType(type, qualifiedName);
+		if (superType == null || superType.isUndefinedType()) {
+			if (superType != null) {
+				// merge with existing type
+				superType.setCElementType(type);
 			} else {
-				IPath path = (IPath) originalRef;
-				location = new TypeReference(path, fProject);
+				// add new type to cache
+				superType = new TypeInfo(type, qualifiedName);
+				fTypeCache.insert(superType);
 			}
-			info.addReference(location);
 		}
+		superType.addDerivedReference(location);
 		
-		TypeReference location;
-		if (resolvedRef instanceof IWorkingCopy) {
-			IWorkingCopy workingCopy = (IWorkingCopy) resolvedRef;
-			location = new TypeReference(workingCopy, fProject, offset, length);
-		} else if (resolvedRef instanceof IResource) {
-			IResource resource = (IResource) resolvedRef;
-			location = new TypeReference(resource, fProject, offset, length);
-		} else {
-			IPath path = (IPath) resolvedRef;
-			location = new TypeReference(path, fProject, offset, length);
+		if (fSuperTypeToFind != null && fSuperTypeToFind.equals(superType)) {
+			//TODO don't need to do anything here?
 		}
-		info.addReference(location);
+		fTypeCache.addSupertype(addToType, superType, access, isVirtual);
+		fTypeCache.addSubtype(superType, addToType);
+		return superType;
 	}
 
 	/* (non-Javadoc)
Index: model/org/eclipse/cdt/internal/core/model/CElement.java
===================================================================
RCS file: /home/tools/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/CElement.java,v
retrieving revision 1.29
diff -u -r1.29 CElement.java
--- model/org/eclipse/cdt/internal/core/model/CElement.java	21 Jun 2004 17:47:54 -0000	1.29
+++ model/org/eclipse/cdt/internal/core/model/CElement.java	14 Jul 2004 19:47:18 -0000
@@ -441,7 +441,7 @@
 	 * Returns true if this element is an ancestor of the given element,
 	 * otherwise false.
 	 */
-	protected boolean isAncestorOf(ICElement e) {
+	public boolean isAncestorOf(ICElement e) {
 		ICElement parent= e.getParent();
 		while (parent != null && !parent.equals(this)) {
 			parent= parent.getParent();
Index: browser/org/eclipse/cdt/core/browser/Signature.java
===================================================================
RCS file: browser/org/eclipse/cdt/core/browser/Signature.java
diff -N browser/org/eclipse/cdt/core/browser/Signature.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ browser/org/eclipse/cdt/core/browser/Signature.java	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,1997 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *     IBM Corporation - added J2SE 1.5 support
+ *******************************************************************************/
+package org.eclipse.cdt.core.browser;
+
+import org.eclipse.cdt.internal.core.CharOperation;
+
+//TODO move this class to CoreModel?
+
+/**
+ * Provides methods for encoding and decoding type and method signature strings.
+ * <p>
+ * Signatures obtained from parsing source (".java") files differ subtly from
+ * ones obtained from pre-compiled binary (".class") files in class names are
+ * usually left unresolved in the former. For example, the normal resolved form
+ * of the type "String" embeds the class's package name ("Ljava.lang.String;"
+ * or "Ljava/lang/String;"), whereas the unresolved form contains only what is
+ * written "QString;".
+ * </p>
+ * <p>
+ * Generic types introduce to the Java language in J2SE 1.5 add three new
+ * facets to signatures: type variables, parameterized types with type arguments,
+ * and formal type parameters. <it>Rich</it> signatures containing these facets
+ * only occur when dealing with code that makes overt use of the new language
+ * features. All other code, and certainly all Java code written or compiled
+ * with J2SE 1.4 or earlier, involved only <it>simple</it> signatures.
+ * </p>
+ * <p>
+ * The syntax for a type signature is:
+ * <pre>
+ * TypeSignature ::=
+ *     "B"  // byte
+ *   | "C"  // char
+ *   | "D"  // double
+ *   | "F"  // float
+ *   | "I"  // int
+ *   | "J"  // long
+ *   | "S"  // short
+ *   | "V"  // void
+ *   | "Z"  // boolean
+ *   | "T" + Identifier + ";" // type variable
+ *   | "[" + TypeSignature  // array X[]
+ *   | ResolvedClassTypeSignature
+ *   | UnresolvedClassTypeSignature
+ * 
+ * ResolvedClassTypeSignature ::= // resolved named type (in compiled code)
+ *     "L" + Identifier + OptionalTypeArguments
+ *           ( ( "." | "/" ) + Identifier + OptionalTypeArguments )* + ";"
+ * 
+ * UnresolvedClassTypeSignature ::= // unresolved named type (in source code)
+ *     "Q" + Identifier + OptionalTypeArguments
+ *           ( ( "." | "/" ) + Identifier + OptionalTypeArguments )* + ";"
+ * 
+ * OptionalTypeArguments ::=
+ *     "&lt;" + TypeArgument+ + "&gt;" 
+ *   |
+ * 
+ * TypeArgument ::=
+ *   | TypeSignature
+ *   | "*" // wildcard ?
+ *   | "+" TypeSignature // wildcard ? extends X
+ *   | "-" TypeSignature // wildcard ? super X
+ * </pre>
+ * </p>
+ * <p>
+ * Examples:
+ * <ul>
+ *   <li><code>"[[I"</code> denotes <code>int[][]</code></li>
+ *   <li><code>"Ljava.lang.String;"</code> denotes <code>java.lang.String</code> in compiled code</li>
+ *   <li><code>"QString;"</code> denotes <code>String</code> in source code</li>
+ *   <li><code>"Qjava.lang.String;"</code> denotes <code>java.lang.String</code> in source code</li>
+ *   <li><code>"[QString;"</code> denotes <code>String[]</code> in source code</li>
+ *   <li><code>"QMap&lt;QString;&ast;&gt;;"</code> denotes <code>Map&lt;String,?&gt;</code> in source code</li>
+ *   <li><code>"Qjava.util.List&ltTV;&gt;;"</code> denotes <code>java.util.List&lt;V&gt;</code> in source code</li>
+ * </ul>
+ * </p>
+ * <p>
+ * The syntax for a method signature is: 
+ * <pre>
+ * MethodSignature ::= "(" + ParamTypeSignature* + ")" + ReturnTypeSignature
+ * ParamTypeSignature ::= TypeSignature
+ * ReturnTypeSignature ::= TypeSignature
+ * </pre>
+ * <p>
+ * Examples:
+ * <ul>
+ *   <li><code>"()I"</code> denotes <code>int foo()</code></li>
+ *   <li><code>"([Ljava.lang.String;)V"</code> denotes <code>void foo(java.lang.String[])</code> in compiled code</li>
+ *   <li><code>"(QString;)QObject;"</code> denotes <code>Object foo(String)</code> in source code</li>
+ * </ul>
+ * </p>
+ * <p>
+ * The syntax for a formal type parameter signature is:
+ * <pre>
+ * FormalTypeParameterSignature ::=
+ *     TypeVariableName + OptionalClassBound + InterfaceBound*
+ * TypeVariableName ::= Identifier
+ * OptionalClassBound ::=
+ *     ":"
+ *   | ":" + TypeSignature
+ * InterfaceBound ::= 
+ *     ":" + TypeSignature
+ * </pre>
+ * <p>
+ * Examples:
+ * <ul>
+ *   <li><code>"X:"</code> denotes <code>X</code></li>
+ *   <li><code>"X:QReader;"</code> denotes <code>X extends Reader</code> in source code</li>
+ *   <li><code>"X:QReader;:QSerializable;"</code> denotes <code>X extends Reader & Serializable</code> in source code</li>
+ * </ul>
+ * </p>
+ * <p>
+ * This class provides static methods and constants only; it is not intended to be
+ * instantiated or subclassed by clients.
+ * </p>
+ */
+public final class Signature {
+
+	/**
+	 * Character constant indicating the primitive type boolean in a signature.
+	 * Value is <code>'Z'</code>.
+	 */
+	public static final char C_BOOLEAN 		= 'Z';
+
+	/**
+	 * Character constant indicating the primitive type byte in a signature.
+	 * Value is <code>'B'</code>.
+	 */
+	public static final char C_BYTE 		= 'B';
+
+	/**
+	 * Character constant indicating the primitive type char in a signature.
+	 * Value is <code>'C'</code>.
+	 */
+	public static final char C_CHAR 		= 'C';
+
+	/**
+	 * Character constant indicating the primitive type double in a signature.
+	 * Value is <code>'D'</code>.
+	 */
+	public static final char C_DOUBLE 		= 'D';
+
+	/**
+	 * Character constant indicating the primitive type float in a signature.
+	 * Value is <code>'F'</code>.
+	 */
+	public static final char C_FLOAT 		= 'F';
+
+	/**
+	 * Character constant indicating the primitive type int in a signature.
+	 * Value is <code>'I'</code>.
+	 */
+	public static final char C_INT 			= 'I';
+	
+	/**
+	 * Character constant indicating the semicolon in a signature.
+	 * Value is <code>';'</code>.
+	 */
+	public static final char C_SEMICOLON 			= ';';
+
+	/**
+	 * Character constant indicating the colon in a signature.
+	 * Value is <code>':'</code>.
+	 * @since 3.0
+	 */
+	public static final char C_COLON 			= ':';
+
+	/**
+	 * Character constant indicating the primitive type long in a signature.
+	 * Value is <code>'J'</code>.
+	 */
+	public static final char C_LONG			= 'J';
+	
+	/**
+	 * Character constant indicating the primitive type short in a signature.
+	 * Value is <code>'S'</code>.
+	 */
+	public static final char C_SHORT		= 'S';
+	
+	/**
+	 * Character constant indicating result type void in a signature.
+	 * Value is <code>'V'</code>.
+	 */
+	public static final char C_VOID			= 'V';
+	
+	/**
+	 * Character constant indicating result const in a signature.
+	 * Value is <code>'K'</code>.
+	 */
+	public static final char C_CONST		= 'K';
+
+	/**
+	 * Character constant indicating the start of a resolved type variable in a 
+	 * signature. Value is <code>'T'</code>.
+	 * @since 3.0
+	 */
+	public static final char C_TYPE_VARIABLE	= 'T';
+	
+	/**
+	 * Character constant indicating a wildcard type argument 
+	 * in a signature.
+	 * Value is <code>'&ast;'</code>.
+	 * @since 3.0
+	 */
+	public static final char C_STAR	= '*';
+	
+	/** 
+	 * Character constant indicating the dot in a signature. 
+	 * Value is <code>'.'</code>.
+	 */
+	public static final char C_DOT			= '.';
+	
+	/** 
+	 * Character constant indicating the dollar in a signature.
+	 * Value is <code>'$'</code>.
+	 */
+	public static final char C_DOLLAR			= '$';
+
+	/** 
+	 * Character constant indicating an array type in a signature.
+	 * Value is <code>'['</code>.
+	 */
+	public static final char C_ARRAY		= '[';
+
+	/** 
+	 * Character constant indicating the start of a resolved, named type in a 
+	 * signature. Value is <code>'L'</code>.
+	 */
+	public static final char C_RESOLVED		= 'L';
+
+	/** 
+	 * Character constant indicating the start of an unresolved, named type in a
+	 * signature. Value is <code>'Q'</code>.
+	 */
+	public static final char C_UNRESOLVED	= 'Q';
+
+	/**
+	 * Character constant indicating the end of a named type in a signature. 
+	 * Value is <code>';'</code>.
+	 */
+	public static final char C_NAME_END		= ';';
+
+	/**
+	 * Character constant indicating the start of a parameter type list in a
+	 * signature. Value is <code>'('</code>.
+	 */
+	public static final char C_PARAM_START	= '(';
+
+	/**
+	 * Character constant indicating the end of a parameter type list in a 
+	 * signature. Value is <code>')'</code>.
+	 */
+	public static final char C_PARAM_END	= ')';
+
+	/**
+	 * Character constant indicating the start of a formal type parameter
+	 * (or type argument) list in a signature. Value is <code>'&lt;'</code>.
+	 * @since 3.0
+	 */
+	public static final char C_GENERIC_START	= '<';
+
+	/**
+	 * Character constant indicating the end of a generic type list in a 
+	 * signature. Value is <code>'%gt;'</code>.
+	 * @since 3.0
+	 */
+	public static final char C_GENERIC_END	= '>';
+
+	/**
+	 * String constant for the signature of the primitive type boolean.
+	 * Value is <code>"Z"</code>.
+	 */
+	public static final String SIG_BOOLEAN 		= "Z"; //$NON-NLS-1$
+
+	/**
+	 * String constant for the signature of the primitive type byte. 
+	 * Value is <code>"B"</code>.
+	 */
+	public static final String SIG_BYTE 		= "B"; //$NON-NLS-1$
+
+	/**
+	 * String constant for the signature of the primitive type char.
+	 * Value is <code>"C"</code>.
+	 */
+	public static final String SIG_CHAR 		= "C"; //$NON-NLS-1$
+
+	/**
+	 * String constant for the signature of the primitive type double.
+	 * Value is <code>"D"</code>.
+	 */
+	public static final String SIG_DOUBLE 		= "D"; //$NON-NLS-1$
+
+	/**
+	 * String constant for the signature of the primitive type float.
+	 * Value is <code>"F"</code>.
+	 */
+	public static final String SIG_FLOAT 		= "F"; //$NON-NLS-1$
+
+	/**
+	 * String constant for the signature of the primitive type int.
+	 * Value is <code>"I"</code>.
+	 */
+	public static final String SIG_INT 			= "I"; //$NON-NLS-1$
+
+	/**
+	 * String constant for the signature of the primitive type long.
+	 * Value is <code>"J"</code>.
+	 */
+	public static final String SIG_LONG			= "J"; //$NON-NLS-1$
+
+	/**
+	 * String constant for the signature of the primitive type short.
+	 * Value is <code>"S"</code>.
+	 */
+	public static final String SIG_SHORT		= "S"; //$NON-NLS-1$
+
+	/** String constant for the signature of result type void.
+	 * Value is <code>"V"</code>.
+	 */
+	public static final String SIG_VOID			= "V"; //$NON-NLS-1$
+	
+
+	/**
+	 * Kind constant for a class type signature.
+	 * @see #getTypeSignatureKind(String)
+	 * @since 3.0
+	 */
+	public static int CLASS_TYPE_SIGNATURE = 1;
+
+	/**
+	 * Kind constant for a base (primitive or void) type signature.
+	 * @see #getTypeSignatureKind(String)
+	 * @since 3.0
+	 */
+	public static int BASE_TYPE_SIGNATURE = 2;
+
+	/**
+	 * Kind constant for a type variable signature.
+	 * @see #getTypeSignatureKind(String)
+	 * @since 3.0
+	 */
+	public static int TYPE_VARIABLE_SIGNATURE = 3;
+
+	/**
+	 * Kind constant for an array type signature.
+	 * @see #getTypeSignatureKind(String)
+	 * @since 3.0
+	 */
+	public static int ARRAY_TYPE_SIGNATURE = 4;
+
+	private static final char[] BOOLEAN = {'b', 'o', 'o', 'l', 'e', 'a', 'n'};
+	private static final char[] BYTE = {'b', 'y', 't', 'e'};
+	private static final char[] CHAR = {'c', 'h', 'a', 'r'};
+	private static final char[] DOUBLE = {'d', 'o', 'u', 'b', 'l', 'e'};
+	private static final char[] FLOAT = {'f', 'l', 'o', 'a', 't'};
+	private static final char[] INT = {'i', 'n', 't'};
+	private static final char[] LONG = {'l', 'o', 'n', 'g'};
+	private static final char[] SHORT = {'s', 'h', 'o', 'r', 't'};
+	private static final char[] VOID = {'v', 'o', 'i', 'd'};
+	private static final char[] CONST = {'c', 'o', 'n', 's', 't'};
+	
+	private static final String EMPTY = new String(CharOperation.NO_CHAR);
+		
+private Signature() {
+	// Not instantiable
+}
+
+private static boolean checkPrimitiveType(char[] primitiveTypeName, char[] typeName) {
+	return CharOperation.fragmentEquals(primitiveTypeName, typeName, 0, true) &&
+		(typeName.length == primitiveTypeName.length
+		 || Character.isWhitespace(typeName[primitiveTypeName.length])
+		 || typeName[primitiveTypeName.length] == C_ARRAY
+		 || typeName[primitiveTypeName.length] == C_DOT);
+}
+
+/**
+ * Creates a new type signature with the given amount of array nesting added 
+ * to the given type signature.
+ *
+ * @param typeSignature the type signature
+ * @param arrayCount the desired number of levels of array nesting
+ * @return the encoded array type signature
+ * 
+ * @since 2.0
+ */
+public static char[] createArraySignature(char[] typeSignature, int arrayCount) {
+	if (arrayCount == 0) return typeSignature;
+	int sigLength = typeSignature.length;
+	char[] result = new char[arrayCount + sigLength];
+	for (int i = 0; i < arrayCount; i++) {
+		result[i] = C_ARRAY;
+	}
+	System.arraycopy(typeSignature, 0, result, arrayCount, sigLength);
+	return result;
+}
+/**
+ * Creates a new type signature with the given amount of array nesting added 
+ * to the given type signature.
+ *
+ * @param typeSignature the type signature
+ * @param arrayCount the desired number of levels of array nesting
+ * @return the encoded array type signature
+ */
+public static String createArraySignature(String typeSignature, int arrayCount) {
+	return new String(createArraySignature(typeSignature.toCharArray(), arrayCount));
+}
+
+/**
+ * Creates a method signature from the given parameter and return type 
+ * signatures. The encoded method signature is dot-based.
+ *
+ * @param parameterTypes the list of parameter type signatures
+ * @param returnType the return type signature
+ * @return the encoded method signature
+ * 
+ * @since 2.0
+ */
+public static char[] createMethodSignature(char[][] parameterTypes, char[] returnType) {
+	int parameterTypesLength = parameterTypes.length;
+	int parameterLength = 0;
+	for (int i = 0; i < parameterTypesLength; i++) {
+		parameterLength += parameterTypes[i].length;
+		
+	}
+	int returnTypeLength = returnType.length;
+	char[] result = new char[1 + parameterLength + 1 + returnTypeLength];
+	result[0] = C_PARAM_START;
+	int index = 1;
+	for (int i = 0; i < parameterTypesLength; i++) {
+		char[] parameterType = parameterTypes[i];
+		int length = parameterType.length;
+		System.arraycopy(parameterType, 0, result, index, length);
+		index += length;
+	}
+	result[index] = C_PARAM_END;
+	System.arraycopy(returnType, 0, result, index+1, returnTypeLength);
+	return result;
+}
+
+/**
+ * Creates a method signature from the given parameter and return type 
+ * signatures. The encoded method signature is dot-based. This method
+ * is equivalent to
+ * <code>createMethodSignature(parameterTypes, returnType)</code>.
+ *
+ * @param parameterTypes the list of parameter type signatures
+ * @param returnType the return type signature
+ * @return the encoded method signature
+ * @see Signature#createMethodSignature(char[][], char[])
+ */
+public static String createMethodSignature(String[] parameterTypes, String returnType) {
+	int parameterTypesLenth = parameterTypes.length;
+	char[][] parameters = new char[parameterTypesLenth][];
+	for (int i = 0; i < parameterTypesLenth; i++) {
+		parameters[i] = parameterTypes[i].toCharArray();
+	}
+	return new String(createMethodSignature(parameters, returnType.toCharArray()));
+}
+
+/**
+ * Creates a new type signature from the given type name encoded as a character
+ * array. The type name may contain primitive types or array types. However,
+ * parameterized types are not supported.
+ * This method is equivalent to
+ * <code>createTypeSignature(new String(typeName),isResolved)</code>, although
+ * more efficient for callers with character arrays rather than strings. If the 
+ * type name is qualified, then it is expected to be dot-based.
+ *
+ * @param typeName the possibly qualified type name
+ * @param isResolved <code>true</code> if the type name is to be considered
+ *   resolved (for example, a type name from a binary class file), and 
+ *   <code>false</code> if the type name is to be considered unresolved
+ *   (for example, a type name found in source code)
+ * @return the encoded type signature
+ * @see #createTypeSignature(java.lang.String,boolean)
+ */
+public static String createTypeSignature(char[] typeName, boolean isResolved) {
+	return new String(createCharArrayTypeSignature(typeName, isResolved));
+}
+/**
+ * Creates a new type signature from the given type name encoded as a character
+ * array. The type name may contain primitive types or array types. However,
+ * parameterized types are not supported.
+ * This method is equivalent to
+ * <code>createTypeSignature(new String(typeName),isResolved).toCharArray()</code>,
+ * although more efficient for callers with character arrays rather than strings.
+ * If the type name is qualified, then it is expected to be dot-based.
+ *
+ * @param typeName the possibly qualified type name
+ * @param isResolved <code>true</code> if the type name is to be considered
+ *   resolved (for example, a type name from a binary class file), and 
+ *   <code>false</code> if the type name is to be considered unresolved
+ *   (for example, a type name found in source code)
+ * @return the encoded type signature
+ * @see #createTypeSignature(java.lang.String,boolean)
+ * 
+ * @since 2.0
+ */
+public static char[] createCharArrayTypeSignature(char[] typeName, boolean isResolved) {
+	if (typeName == null) throw new IllegalArgumentException("null"); //$NON-NLS-1$
+	int length = typeName.length;
+	if (length == 0) throw new IllegalArgumentException(new String(typeName));
+
+	int arrayCount = CharOperation.occurencesOf('[', typeName);
+	char[] sig;
+	
+	switch (typeName[0]) {
+		// primitive type?
+		case 'b' :
+			if (checkPrimitiveType(BOOLEAN, typeName)) {
+				sig = new char[arrayCount+1];
+				sig[arrayCount] = C_BOOLEAN;
+				break;
+			} else if (checkPrimitiveType(BYTE, typeName)) {
+				sig = new char[arrayCount+1];
+				sig[arrayCount] = C_BYTE;
+				break;
+			}
+		case 'c':
+			if (checkPrimitiveType(CHAR, typeName)) {
+				sig = new char[arrayCount+1];
+				sig[arrayCount] = C_CHAR;
+				break;
+			}
+		case 'd':
+			if (checkPrimitiveType(DOUBLE, typeName)) {
+				sig = new char[arrayCount+1];
+				sig[arrayCount] = C_DOUBLE;
+				break;
+			}
+		case 'f':
+			if (checkPrimitiveType(FLOAT, typeName)) {
+				sig = new char[arrayCount+1];
+				sig[arrayCount] = C_FLOAT;
+				break;
+			}
+		case 'i':
+			if (checkPrimitiveType(INT, typeName)) {
+				sig = new char[arrayCount+1];
+				sig[arrayCount] = C_INT;
+				break;
+			}
+		case 'l':
+			if (checkPrimitiveType(LONG, typeName)) {
+				sig = new char[arrayCount+1];
+				sig[arrayCount] = C_LONG;
+				break;
+			}
+		case 's':
+			if (checkPrimitiveType(SHORT, typeName)) {
+				sig = new char[arrayCount+1];
+				sig[arrayCount] = C_SHORT;
+				break;
+			}
+		case 'v':
+			if (checkPrimitiveType(VOID, typeName)) {
+				sig = new char[arrayCount+1];
+				sig[arrayCount] = C_VOID;
+				break;
+			}
+		default:
+			// non primitive type
+			int sigLength = arrayCount + 1 + length + 1; // for example '[[[Ljava.lang.String;'
+			sig = new char[sigLength];
+			int sigIndex = arrayCount+1; // index in sig
+			int startID = 0; // start of current ID in typeName
+			int index = 0; // index in typeName
+			while (index < length) {
+				char currentChar = typeName[index];
+				switch (currentChar) {
+					case '.':
+						if (startID == -1) throw new IllegalArgumentException(new String(typeName));
+						if (startID < index) {
+							sig = CharOperation.append(sig, sigIndex, typeName, startID, index);
+							sigIndex += index-startID;
+						}
+						sig[sigIndex++] = C_DOT;
+						index++;
+						startID = index;
+						break;
+					case '[':
+						if (startID != -1) {
+							if (startID < index) {
+								sig = CharOperation.append(sig, sigIndex, typeName, startID, index);
+								sigIndex += index-startID;
+							}
+							startID = -1; // no more id after []
+						}
+						index++;
+						break;
+					default :
+						if (startID != -1 && CharOperation.isWhitespace(currentChar)) {
+							if (startID < index) {
+								sig = CharOperation.append(sig, sigIndex, typeName, startID, index);
+								sigIndex += index-startID;
+							}
+							startID = index+1;
+						}
+						index++;
+						break;
+				}
+			}
+			// last id
+			if (startID != -1 && startID < index) {
+				sig = CharOperation.append(sig, sigIndex, typeName, startID, index);
+				sigIndex += index-startID;
+			}
+			
+			// add L (or Q) at the beigininig and ; at the end
+			sig[arrayCount] = isResolved ? C_RESOLVED : C_UNRESOLVED;
+			sig[sigIndex++] = C_NAME_END;
+			
+			// resize if needed
+			if (sigLength > sigIndex) {
+				System.arraycopy(sig, 0, sig = new char[sigIndex], 0, sigIndex);
+			}
+	}
+
+	// add array info
+	for (int i = 0; i < arrayCount; i++) {
+		sig[i] = C_ARRAY;
+	}
+	
+	return sig;
+}
+/**
+ * Creates a new type signature from the given type name. If the type name is qualified,
+ * then it is expected to be dot-based. The type name may contain primitive
+ * types or array types. However, parameterized types are not supported.
+ * <p>
+ * For example:
+ * <pre>
+ * <code>
+ * createTypeSignature("int", hucairz) -> "I"
+ * createTypeSignature("java.lang.String", true) -> "Ljava.lang.String;"
+ * createTypeSignature("String", false) -> "QString;"
+ * createTypeSignature("java.lang.String", false) -> "Qjava.lang.String;"
+ * createTypeSignature("int []", false) -> "[I"
+ * </code>
+ * </pre>
+ * </p>
+ *
+ * @param typeName the possibly qualified type name
+ * @param isResolved <code>true</code> if the type name is to be considered
+ *   resolved (for example, a type name from a binary class file), and 
+ *   <code>false</code> if the type name is to be considered unresolved
+ *   (for example, a type name found in source code)
+ * @return the encoded type signature
+ */
+public static String createTypeSignature(String typeName, boolean isResolved) {
+	return createTypeSignature(typeName == null ? null : typeName.toCharArray(), isResolved);
+}
+
+/**
+ * Returns the array count (array nesting depth) of the given type signature.
+ *
+ * @param typeSignature the type signature
+ * @return the array nesting depth, or 0 if not an array
+ * @exception IllegalArgumentException if the signature is not syntactically
+ *   correct
+ * 
+ * @since 2.0
+ */
+public static int getArrayCount(char[] typeSignature) throws IllegalArgumentException {	
+	try {
+		int count = 0;
+		while (typeSignature[count] == C_ARRAY) {
+			++count;
+		}
+		return count;
+	} catch (ArrayIndexOutOfBoundsException e) { // signature is syntactically incorrect if last character is C_ARRAY
+		throw new IllegalArgumentException();
+	}
+}
+/**
+ * Returns the array count (array nesting depth) of the given type signature.
+ *
+ * @param typeSignature the type signature
+ * @return the array nesting depth, or 0 if not an array
+ * @exception IllegalArgumentException if the signature is not syntactically
+ *   correct
+ */
+public static int getArrayCount(String typeSignature) throws IllegalArgumentException {
+	return getArrayCount(typeSignature.toCharArray());
+}
+/**
+ * Returns the type signature without any array nesting.
+ * <p>
+ * For example:
+ * <pre>
+ * <code>
+ * getElementType({'[', '[', 'I'}) --> {'I'}.
+ * </code>
+ * </pre>
+ * </p>
+ * 
+ * @param typeSignature the type signature
+ * @return the type signature without arrays
+ * @exception IllegalArgumentException if the signature is not syntactically
+ *   correct
+ * 
+ * @since 2.0
+ */
+public static char[] getElementType(char[] typeSignature) throws IllegalArgumentException {
+	int count = getArrayCount(typeSignature);
+	if (count == 0) return typeSignature;
+	int length = typeSignature.length;
+	char[] result = new char[length-count];
+	System.arraycopy(typeSignature, count, result, 0, length-count);
+	return result;
+}
+/**
+ * Returns the type signature without any array nesting.
+ * <p>
+ * For example:
+ * <pre>
+ * <code>
+ * getElementType("[[I") --> "I".
+ * </code>
+ * </pre>
+ * </p>
+ * 
+ * @param typeSignature the type signature
+ * @return the type signature without arrays
+ * @exception IllegalArgumentException if the signature is not syntactically
+ *   correct
+ */
+public static String getElementType(String typeSignature) throws IllegalArgumentException {
+	return new String(getElementType(typeSignature.toCharArray()));
+}
+/**
+ * Returns the number of parameter types in the given method signature.
+ *
+ * @param methodSignature the method signature
+ * @return the number of parameters
+ * @exception IllegalArgumentException if the signature is not syntactically
+ *   correct
+ * @since 2.0
+ */
+public static int getParameterCount(char[] methodSignature) throws IllegalArgumentException {
+	try {
+		int count = 0;
+		int i = CharOperation.indexOf(C_PARAM_START, methodSignature);
+		if (i < 0) {
+			throw new IllegalArgumentException();
+		} else {
+			i++;
+		}
+		for (;;) {
+			if (methodSignature[i] == C_PARAM_END) {
+				return count;
+			}
+			int e= scanTypeSignature(methodSignature, i);
+			if (e < 0) {
+				throw new IllegalArgumentException();
+			} else {
+				i = e + 1;
+			}
+			count++;
+		}
+	} catch (ArrayIndexOutOfBoundsException e) {
+		throw new IllegalArgumentException();
+	}
+}
+
+/**
+ * Returns the kind of type signature encoded by the given string.
+ * 
+ * @param typeSignature the type signature string
+ * @return the kind of type signature; one of the kind constants:
+ * {@link #ARRAY_TYPE_SIGNATURE}, {@link #CLASS_TYPE_SIGNATURE},
+ * {@link #BASE_TYPE_SIGNATURE}, or {@link #TYPE_VARIABLE_SIGNATURE}
+ * @exception IllegalArgumentException if this is not a type signature
+ * @since 3.0
+ */
+public static int getTypeSignatureKind(char[] typeSignature) {
+	// need a minimum 1 char
+	if (typeSignature.length < 1) {
+		throw new IllegalArgumentException();
+	}
+	char c = typeSignature[0];
+	switch (c) {
+		case C_ARRAY :
+			return ARRAY_TYPE_SIGNATURE;
+		case C_RESOLVED :
+		case C_UNRESOLVED :
+			return CLASS_TYPE_SIGNATURE;
+		case C_TYPE_VARIABLE :
+			return TYPE_VARIABLE_SIGNATURE;
+		case C_BOOLEAN :
+		case C_BYTE :
+		case C_CHAR :
+		case C_DOUBLE :
+		case C_FLOAT :
+		case C_INT :
+		case C_LONG :
+		case C_SHORT :
+		case C_VOID :
+			return BASE_TYPE_SIGNATURE;
+		default :
+			throw new IllegalArgumentException();
+	}
+}
+
+/**
+ * Returns the kind of type signature encoded by the given string.
+ * 
+ * @param typeSignature the type signature string
+ * @return the kind of type signature; one of the kind constants:
+ * {@link #ARRAY_TYPE_SIGNATURE}, {@link #CLASS_TYPE_SIGNATURE},
+ * {@link #BASE_TYPE_SIGNATURE}, or {@link #TYPE_VARIABLE_SIGNATURE}
+ * @exception IllegalArgumentException if this is not a type signature
+ * @since 3.0
+ */
+public static int getTypeSignatureKind(String typeSignature) {
+	// need a minimum 1 char
+	if (typeSignature.length() < 1) {
+		throw new IllegalArgumentException();
+	}
+	char c = typeSignature.charAt(0);
+	switch (c) {
+		case C_ARRAY :
+			return ARRAY_TYPE_SIGNATURE;
+		case C_RESOLVED :
+		case C_UNRESOLVED :
+			return CLASS_TYPE_SIGNATURE;
+		case C_TYPE_VARIABLE :
+			return TYPE_VARIABLE_SIGNATURE;
+		case C_BOOLEAN :
+		case C_BYTE :
+		case C_CHAR :
+		case C_DOUBLE :
+		case C_FLOAT :
+		case C_INT :
+		case C_LONG :
+		case C_SHORT :
+		case C_VOID :
+			return BASE_TYPE_SIGNATURE;
+		default :
+			throw new IllegalArgumentException();
+	}
+}
+
+/**
+ * Scans the given string for a type signature starting at the given index
+ * and returns the index of the last character.
+ * <pre>
+ * TypeSignature:
+ *  |  BaseTypeSignature
+ *  |  ArrayTypeSignature
+ *  |  ClassTypeSignature
+ *  |  TypeVariableSignature
+ * </pre>
+ * 
+ * @param string the signature string
+ * @param start the 0-based character index of the first character
+ * @return the 0-based character index of the last character
+ * @exception IllegalArgumentException if this is not a type signature
+ * @see #appendTypeSignature(char[], int, boolean, StringBuffer)
+ */
+private static int scanTypeSignature(char[] string, int start) {
+	// need a minimum 1 char
+	if (start >= string.length) {
+		throw new IllegalArgumentException();
+	}
+	char c = string[start];
+	switch (c) {
+		case C_ARRAY :
+			return scanArrayTypeSignature(string, start);
+		case C_RESOLVED :
+		case C_UNRESOLVED :
+			return scanClassTypeSignature(string, start);
+		case C_TYPE_VARIABLE :
+			return scanTypeVariableSignature(string, start);
+		case C_BOOLEAN :
+		case C_BYTE :
+		case C_CHAR :
+		case C_DOUBLE :
+		case C_FLOAT :
+		case C_INT :
+		case C_LONG :
+		case C_SHORT :
+		case C_VOID :
+			return scanBaseTypeSignature(string, start);
+		default :
+			throw new IllegalArgumentException();
+	}
+}
+
+/**
+ * Scans the given string for a base type signature starting at the given index
+ * and returns the index of the last character.
+ * <pre>
+ * BaseTypeSignature:
+ *     <b>B</b> | <b>C</b> | <b>D</b> | <b>F</b> | <b>I</b>
+ *   | <b>J</b> | <b>S</b> | <b>V</b> | <b>Z</b>
+ * </pre>
+ * Note that although the base type "V" is only allowed in method return types,
+ * there is no syntactic ambiguity. This method will accept them anywhere
+ * without complaint.
+ * 
+ * @param string the signature string
+ * @param start the 0-based character index of the first character
+ * @return the 0-based character index of the last character
+ * @exception IllegalArgumentException if this is not a base type signature
+ */
+private static int scanBaseTypeSignature(char[] string, int start) {
+	// need a minimum 1 char
+	if (start >= string.length) {
+		throw new IllegalArgumentException();
+	}
+	char c = string[start];
+	if ("BCDFIJSVZ".indexOf(c) >= 0) { //$NON-NLS-1$
+		return start;
+	} else {
+		throw new IllegalArgumentException();
+	}
+}
+
+/**
+ * Scans the given string for an array type signature starting at the given
+ * index and returns the index of the last character.
+ * <pre>
+ * ArrayTypeSignature:
+ *     <b>[</b> TypeSignature
+ * </pre>
+ * 
+ * @param string the signature string
+ * @param start the 0-based character index of the first character
+ * @return the 0-based character index of the last character
+ * @exception IllegalArgumentException if this is not an array type signature
+ * @see #appendArrayTypeSignature(char[], int, boolean, StringBuffer)
+ */
+private static int scanArrayTypeSignature(char[] string, int start) {
+	// need a minimum 2 char
+	if (start >= string.length - 1) {
+		throw new IllegalArgumentException();
+	}
+	char c = string[start];
+	if (c != C_ARRAY) { //$NON-NLS-1$
+		throw new IllegalArgumentException();
+	}
+	return scanTypeSignature(string, start + 1);
+}
+
+/**
+ * Scans the given string for a type variable signature starting at the given
+ * index and returns the index of the last character.
+ * <pre>
+ * TypeVariableSignature:
+ *     <b>T</b> Identifier <b>;</b>
+ * </pre>
+ * 
+ * @param string the signature string
+ * @param start the 0-based character index of the first character
+ * @return the 0-based character index of the last character
+ * @exception IllegalArgumentException if this is not a type variable signature
+ */
+private static int scanTypeVariableSignature(char[] string, int start) {
+	// need a minimum 3 chars "Tx;"
+	if (start >= string.length - 2) { 
+		throw new IllegalArgumentException();
+	}
+	// must start in "T"
+	char c = string[start];
+	if (c != C_TYPE_VARIABLE) {
+		throw new IllegalArgumentException();
+	}
+	int id = scanIdentifier(string, start + 1);
+	c = string[id + 1];
+	if (c == C_SEMICOLON) {
+		return id + 1;
+	} else {
+		throw new IllegalArgumentException();
+	}
+}
+
+/**
+ * Scans the given string for an identifier starting at the given
+ * index and returns the index of the last character. 
+ * Stop characters are: ";", ":", "&lt;", "&gt;", "/", ".".
+ * 
+ * @param string the signature string
+ * @param start the 0-based character index of the first character
+ * @return the 0-based character index of the last character
+ * @exception IllegalArgumentException if this is not an identifier
+ */
+private static int scanIdentifier(char[] string, int start) {
+	// need a minimum 1 char
+	if (start >= string.length) { 
+		throw new IllegalArgumentException();
+	}
+	int p = start;
+	while (true) {
+		char c = string[p];
+		if (c == '<' || c == '>' || c == ':' || c == ';' || c == '.' || c == '/') {
+			return p - 1;
+		}
+		p++;
+		if (p == string.length) {
+			return p - 1;
+		}
+	}
+}
+
+/**
+ * Scans the given string for a class type signature starting at the given
+ * index and returns the index of the last character.
+ * <pre>
+ * ClassTypeSignature:
+ *     { <b>L</b> | <b>Q</b> } Identifier
+ *           { { <b>/</b> | <b>.</b> Identifier [ <b>&lt;</b> TypeArgumentSignature* <b>&gt;</b> ] }
+ *           <b>;</b>
+ * </pre>
+ * Note that although all "/"-identifiers most come before "."-identifiers,
+ * there is no syntactic ambiguity. This method will accept them without
+ * complaint.
+ * 
+ * @param string the signature string
+ * @param start the 0-based character index of the first character
+ * @return the 0-based character index of the last character
+ * @exception IllegalArgumentException if this is not a class type signature
+ * @see #appendClassTypeSignature(char[], int, boolean, StringBuffer)
+ */
+private static int scanClassTypeSignature(char[] string, int start) {
+	// need a minimum 3 chars "Lx;"
+	if (start >= string.length - 2) { 
+		throw new IllegalArgumentException();
+	}
+	// must start in "L" or "Q"
+	char c = string[start];
+	if (c != C_RESOLVED && c != C_UNRESOLVED) {
+		return -1;
+	}
+	int p = start + 1;
+	while (true) {
+		if (p >= string.length) {
+			throw new IllegalArgumentException();
+		}
+		c = string[p];
+		if (c == C_SEMICOLON) {
+			// all done
+			return p;
+		} else if (c == C_GENERIC_START) {
+			int e = scanTypeArgumentSignatures(string, p);
+			p = e;
+		} else if (c == C_DOT || c == '/') {
+			int id = scanIdentifier(string, p + 1);
+			p = id;
+		}
+		p++;
+	}
+}
+
+/**
+ * Scans the given string for a list of type argument signatures starting at
+ * the given index and returns the index of the last character.
+ * <pre>
+ * TypeArgumentSignatures:
+ *     <b>&lt;</b> TypeArgumentSignature* <b>&gt;</b>
+ * </pre>
+ * Note that although there is supposed to be at least one type argument, there
+ * is no syntactic ambiguity if there are none. This method will accept zero
+ * type argument signatures without complaint.
+ * 
+ * @param string the signature string
+ * @param start the 0-based character index of the first character
+ * @return the 0-based character index of the last character
+ * @exception IllegalArgumentException if this is not a list of type arguments
+ * signatures
+ * @see #appendTypeArgumentSignatures(char[], int, boolean, StringBuffer)
+ */
+private static int scanTypeArgumentSignatures(char[] string, int start) {
+	// need a minimum 2 char "<>"
+	if (start >= string.length - 1) {
+		throw new IllegalArgumentException();
+	}
+	char c = string[start];
+	if (c != C_GENERIC_START) {
+		throw new IllegalArgumentException();
+	}
+	int p = start + 1;
+	while (true) {
+		if (p >= string.length) {
+			throw new IllegalArgumentException();
+		}
+		c = string[p];
+		if (c == C_GENERIC_END) {
+			return p;
+		}
+		int e = scanTypeArgumentSignature(string, p);
+		p = e + 1;
+	}
+}
+
+/**
+ * Scans the given string for a type argument signature starting at the given
+ * index and returns the index of the last character.
+ * <pre>
+ * TypeArgumentSignature:
+ *     <b>&#42;</b>
+ *  |  <b>+</b> TypeSignature
+ *  |  <b>-</b> TypeSignature
+ *  |  TypeSignature
+ * </pre>
+ * Note that although base types are not allowed in type arguments, there is
+ * no syntactic ambiguity. This method will accept them without complaint.
+ * 
+ * @param string the signature string
+ * @param start the 0-based character index of the first character
+ * @return the 0-based character index of the last character
+ * @exception IllegalArgumentException if this is not a type argument signature
+ * @see #appendTypeArgumentSignature(char[], int, boolean, StringBuffer)
+ */
+private static int scanTypeArgumentSignature(char[] string, int start) {
+	// need a minimum 1 char
+	if (start >= string.length) {
+		throw new IllegalArgumentException();
+	}
+	char c = string[start];
+	if (c == C_STAR) {
+		return start;
+	}
+	if (c == '+' || c == '-') {
+		return scanTypeSignature(string, start + 1);
+	} else {
+		return scanTypeSignature(string, start);
+	}
+}
+
+/**
+ * Returns the number of parameter types in the given method signature.
+ *
+ * @param methodSignature the method signature
+ * @return the number of parameters
+ * @exception IllegalArgumentException if the signature is not syntactically
+ *   correct
+ */
+public static int getParameterCount(String methodSignature) throws IllegalArgumentException {
+	return getParameterCount(methodSignature.toCharArray());
+}
+/**
+ * Extracts the parameter type signatures from the given method signature. 
+ * The method signature is expected to be dot-based.
+ *
+ * @param methodSignature the method signature
+ * @return the list of parameter type signatures
+ * @exception IllegalArgumentException if the signature is syntactically
+ *   incorrect
+ * 
+ * @since 2.0
+ */
+public static char[][] getParameterTypes(char[] methodSignature) throws IllegalArgumentException {
+	try {
+		int count = getParameterCount(methodSignature);
+		char[][] result = new char[count][];
+		if (count == 0) {
+			return result;
+		}
+		int i = CharOperation.indexOf(C_PARAM_START, methodSignature);
+		if (i < 0) {
+			throw new IllegalArgumentException();
+		} else {
+			i++;
+		}
+		int t = 0;
+		for (;;) {
+			if (methodSignature[i] == C_PARAM_END) {
+				return result;
+			}
+			int e = scanTypeSignature(methodSignature, i);
+			if (e < 0) {
+				throw new IllegalArgumentException();
+			}
+			result[t] = CharOperation.subarray(methodSignature, i, e + 1);
+			t++;
+			i = e + 1;
+		}
+	} catch (ArrayIndexOutOfBoundsException e) {
+		throw new IllegalArgumentException();
+	}
+}
+/**
+ * Extracts the parameter type signatures from the given method signature. 
+ * The method signature is expected to be dot-based.
+ *
+ * @param methodSignature the method signature
+ * @return the list of parameter type signatures
+ * @exception IllegalArgumentException if the signature is syntactically
+ *   incorrect
+ */
+public static String[] getParameterTypes(String methodSignature) throws IllegalArgumentException {
+	char[][] parameterTypes = getParameterTypes(methodSignature.toCharArray());
+	int length = parameterTypes.length;
+	String[] result = new String[length];
+	for (int i = 0; i < length; i++) {
+		result[i] = new String(parameterTypes[i]);
+	}
+	return result;
+}
+
+/**
+ * Extracts the type variable name from the given formal type parameter
+ * signature. The signature is expected to be dot-based.
+ *
+ * @param formalTypeParameterSignature the formal type parameter signature
+ * @return the name of the type variable
+ * @exception IllegalArgumentException if the signature is syntactically
+ *   incorrect
+ * @since 3.0
+ */
+public static String getTypeVariable(String formalTypeParameterSignature) throws IllegalArgumentException {
+	return new String(getTypeVariable(formalTypeParameterSignature.toCharArray()));
+}
+
+/**
+ * Extracts the type variable name from the given formal type parameter
+ * signature. The signature is expected to be dot-based.
+ *
+ * @param formalTypeParameterSignature the formal type parameter signature
+ * @return the name of the type variable
+ * @exception IllegalArgumentException if the signature is syntactically
+ *   incorrect
+ * @since 3.0
+ */
+public static char[] getTypeVariable(char[] formalTypeParameterSignature) throws IllegalArgumentException {
+	int p = CharOperation.indexOf(C_COLON, formalTypeParameterSignature);
+	if (p < 0) {
+		// no ":" means can't be a formal type parameter signature
+		throw new IllegalArgumentException();
+	}
+	return CharOperation.subarray(formalTypeParameterSignature, 0, p);
+}
+
+/**
+ * Extracts the class and interface bounds from the given formal type
+ * parameter signature. The class bound, if present, is listed before
+ * the interface bounds. The signature is expected to be dot-based.
+ *
+ * @param formalTypeParameterSignature the formal type parameter signature
+ * @return the (possibly empty) list of type signatures for the bounds
+ * @exception IllegalArgumentException if the signature is syntactically
+ *   incorrect
+ * @since 3.0
+ */
+public static char[][] getTypeParameterBounds(char[] formalTypeParameterSignature) throws IllegalArgumentException {
+	int p1 = CharOperation.indexOf(C_COLON, formalTypeParameterSignature);
+	if (p1 < 0) {
+		// no ":" means can't be a formal type parameter signature
+		throw new IllegalArgumentException();
+	}
+	if (p1 == formalTypeParameterSignature.length - 1) {
+		// no class or interface bounds
+		return CharOperation.NO_CHAR_CHAR;
+	}
+	int p2 = CharOperation.indexOf(C_COLON, formalTypeParameterSignature, p1 + 1);
+	char[] classBound;
+	if (p2 < 0) {
+		// no interface bounds
+		classBound = CharOperation.subarray(formalTypeParameterSignature, p1 + 1, formalTypeParameterSignature.length);
+		return new char[][] {classBound};
+	}
+	if (p2 == p1 + 1) {
+		// no class bound, but 1 or more interface bounds
+		classBound = null;
+	} else {
+		classBound = CharOperation.subarray(formalTypeParameterSignature, p1 + 1, p2);
+	}
+	char[][] interfaceBounds = CharOperation.splitOn(C_COLON, formalTypeParameterSignature, p2 + 1, formalTypeParameterSignature.length);
+	if (classBound == null) {
+		return interfaceBounds;
+	}
+	int resultLength = interfaceBounds.length + 1;
+	char[][] result = new char[resultLength][];
+	result[0] = classBound;
+	System.arraycopy(interfaceBounds, 0, result, 1, interfaceBounds.length);
+	return result;
+}
+
+/**
+ * Extracts the class and interface bounds from the given formal type
+ * parameter signature. The class bound, if present, is listed before
+ * the interface bounds. The signature is expected to be dot-based.
+ *
+ * @param formalTypeParameterSignature the formal type parameter signature
+ * @return the (possibly empty) list of type signatures for the bounds
+ * @exception IllegalArgumentException if the signature is syntactically
+ *   incorrect
+ * @since 3.0
+ */
+public static String[] getTypeParameterBounds(String formalTypeParameterSignature) throws IllegalArgumentException {
+	char[][] bounds = getTypeParameterBounds(formalTypeParameterSignature.toCharArray());
+	int length = bounds.length;
+	String[] result = new String[length];
+	for (int i = 0; i < length; i++) {
+		result[i] = new String(bounds[i]);
+	}
+	return result;
+}
+
+/**
+ * Returns a char array containing all but the last segment of the given 
+ * dot-separated qualified name. Returns the empty char array if it is not qualified.
+ * <p>
+ * For example:
+ * <pre>
+ * <code>
+ * getQualifier({'j', 'a', 'v', 'a', '.', 'l', 'a', 'n', 'g', '.', 'O', 'b', 'j', 'e', 'c', 't'}) -> {'j', 'a', 'v', 'a', '.', 'l', 'a', 'n', 'g'}
+ * getQualifier({'O', 'u', 't', 'e', 'r', '.', 'I', 'n', 'n', 'e', 'r'}) -> {'O', 'u', 't', 'e', 'r'}
+ * </code>
+ * </pre>
+ * </p>
+ *
+ * @param name the name
+ * @return the qualifier prefix, or the empty char array if the name contains no
+ *   dots
+ * @exception NullPointerException if name is null
+ * @since 2.0
+ */
+public static char[] getQualifier(char[] name) {
+	int lastDot = CharOperation.lastIndexOf(C_DOT, name);
+	if (lastDot == -1) {
+		return CharOperation.NO_CHAR;
+	}
+	return CharOperation.subarray(name, 0, lastDot);
+}
+/**
+ * Returns a string containing all but the last segment of the given 
+ * dot-separated qualified name. Returns the empty string if it is not qualified.
+ * <p>
+ * For example:
+ * <pre>
+ * <code>
+ * getQualifier("java.lang.Object") -> "java.lang"
+ * getQualifier("Outer.Inner") -> "Outer"
+ * </code>
+ * </pre>
+ * </p>
+ *
+ * @param name the name
+ * @return the qualifier prefix, or the empty string if the name contains no
+ *   dots
+ * @exception NullPointerException if name is null
+ */
+public static String getQualifier(String name) {
+	int lastDot = name.lastIndexOf(C_DOT);
+	if (lastDot == -1) {
+		return EMPTY;
+	}
+	return name.substring(0, lastDot);
+}
+/**
+ * Extracts the return type from the given method signature. The method signature is 
+ * expected to be dot-based.
+ *
+ * @param methodSignature the method signature
+ * @return the type signature of the return type
+ * @exception IllegalArgumentException if the signature is syntactically
+ *   incorrect
+ * 
+ * @since 2.0
+ */
+public static char[] getReturnType(char[] methodSignature) throws IllegalArgumentException {
+	// skip type parameters
+	int i = CharOperation.lastIndexOf(C_PARAM_END, methodSignature);
+	if (i == -1) {
+		throw new IllegalArgumentException();
+	}
+	// ignore any thrown exceptions
+	int j = CharOperation.indexOf('^', methodSignature);
+	int last = (j == -1 ? methodSignature.length : j);
+	return CharOperation.subarray(methodSignature, i + 1, last);
+}
+/**
+ * Extracts the return type from the given method signature. The method signature is 
+ * expected to be dot-based.
+ *
+ * @param methodSignature the method signature
+ * @return the type signature of the return type
+ * @exception IllegalArgumentException if the signature is syntactically
+ *   incorrect
+ */
+public static String getReturnType(String methodSignature) throws IllegalArgumentException {
+	return new String(getReturnType(methodSignature.toCharArray()));
+}
+/**
+ * Returns the last segment of the given dot-separated qualified name.
+ * Returns the given name if it is not qualified.
+ * <p>
+ * For example:
+ * <pre>
+ * <code>
+ * getSimpleName({'j', 'a', 'v', 'a', '.', 'l', 'a', 'n', 'g', '.', 'O', 'b', 'j', 'e', 'c', 't'}) -> {'O', 'b', 'j', 'e', 'c', 't'}
+ * </code>
+ * </pre>
+ * </p>
+ *
+ * @param name the name
+ * @return the last segment of the qualified name
+ * @exception NullPointerException if name is null
+ * @since 2.0
+ */
+public static char[] getSimpleName(char[] name) {
+	int lastDot = CharOperation.lastIndexOf(C_DOT, name);
+	if (lastDot == -1) {
+		return name;
+	}
+	return CharOperation.subarray(name, lastDot + 1, name.length);
+}
+/**
+ * Returns the last segment of the given dot-separated qualified name.
+ * Returns the given name if it is not qualified.
+ * <p>
+ * For example:
+ * <pre>
+ * <code>
+ * getSimpleName("java.lang.Object") -> "Object"
+ * </code>
+ * </pre>
+ * </p>
+ *
+ * @param name the name
+ * @return the last segment of the qualified name
+ * @exception NullPointerException if name is null
+ */
+public static String getSimpleName(String name) {
+	int lastDot = name.lastIndexOf(C_DOT);
+	if (lastDot == -1) {
+		return name;
+	}
+	return name.substring(lastDot + 1, name.length());
+}
+/**
+ * Returns all segments of the given dot-separated qualified name.
+ * Returns an array with only the given name if it is not qualified.
+ * Returns an empty array if the name is empty.
+ * <p>
+ * For example:
+ * <pre>
+ * <code>
+ * getSimpleNames({'j', 'a', 'v', 'a', '.', 'l', 'a', 'n', 'g', '.', 'O', 'b', 'j', 'e', 'c', 't'}) -> {{'j', 'a', 'v', 'a'}, {'l', 'a', 'n', 'g'}, {'O', 'b', 'j', 'e', 'c', 't'}}
+ * getSimpleNames({'O', 'b', 'j', 'e', 'c', 't'}) -> {{'O', 'b', 'j', 'e', 'c', 't'}}
+ * getSimpleNames("") -> {}
+ * </code>
+ * </pre>
+ *
+ * @param name the name
+ * @return the list of simple names, possibly empty
+ * @exception NullPointerException if name is null
+ * @since 2.0
+ */
+public static char[][] getSimpleNames(char[] name) {
+	if (name.length == 0) {
+		return CharOperation.NO_CHAR_CHAR;
+	}
+	int dot = CharOperation.indexOf(C_DOT, name);
+	if (dot == -1) {
+		return new char[][] {name};
+	}
+	int n = 1;
+	while ((dot = CharOperation.indexOf(C_DOT, name, dot + 1)) != -1) {
+		++n;
+	}
+	char[][] result = new char[n + 1][];
+	int segStart = 0;
+	for (int i = 0; i < n; ++i) {
+		dot = CharOperation.indexOf(C_DOT, name, segStart);
+		result[i] = CharOperation.subarray(name, segStart, dot);
+		segStart = dot + 1;
+	}
+	result[n] = CharOperation.subarray(name, segStart, name.length);
+	return result;
+}
+/**
+ * Returns all segments of the given dot-separated qualified name.
+ * Returns an array with only the given name if it is not qualified.
+ * Returns an empty array if the name is empty.
+ * <p>
+ * For example:
+ * <pre>
+ * <code>
+ * getSimpleNames("java.lang.Object") -> {"java", "lang", "Object"}
+ * getSimpleNames("Object") -> {"Object"}
+ * getSimpleNames("") -> {}
+ * </code>
+ * </pre>
+ *
+ * @param name the name
+ * @return the list of simple names, possibly empty
+ * @exception NullPointerException if name is null
+ */
+public static String[] getSimpleNames(String name) {
+	char[][] simpleNames = getSimpleNames(name.toCharArray());
+	int length = simpleNames.length;
+	String[] result = new String[length];
+	for (int i = 0; i < length; i++) {
+		result[i] = new String(simpleNames[i]);
+	}
+	return result;
+}
+/**
+ * Converts the given method signature to a readable form. The method signature is expected to
+ * be dot-based.
+ * <p>
+ * For example:
+ * <pre>
+ * <code>
+ * toString("([Ljava.lang.String;)V", "main", new String[] {"args"}, false, true) -> "void main(String[] args)"
+ * </code>
+ * </pre>
+ * </p>
+ * 
+ * @param methodSignature the method signature to convert
+ * @param methodName the name of the method to insert in the result, or 
+ *   <code>null</code> if no method name is to be included
+ * @param parameterNames the parameter names to insert in the result, or 
+ *   <code>null</code> if no parameter names are to be included; if supplied,
+ *   the number of parameter names must match that of the method signature
+ * @param fullyQualifyTypeNames <code>true</code> if type names should be fully
+ *   qualified, and <code>false</code> to use only simple names
+ * @param includeReturnType <code>true</code> if the return type is to be
+ *   included
+ * @return the char array representation of the method signature
+ * 
+ * @since 2.0
+ */
+public static char[] toCharArray(char[] methodSignature, char[] methodName, char[][] parameterNames, boolean fullyQualifyTypeNames, boolean includeReturnType) {
+	int firstParen = CharOperation.indexOf(C_PARAM_START, methodSignature);
+	if (firstParen == -1) {
+		throw new IllegalArgumentException();
+	}
+	
+	StringBuffer buffer = new StringBuffer(methodSignature.length + 10);
+	
+	// return type
+	if (includeReturnType) {
+		char[] rts = getReturnType(methodSignature);
+		appendTypeSignature(rts, 0 , fullyQualifyTypeNames, buffer);
+		buffer.append(' ');
+	}
+	
+	// selector
+	if (methodName != null) {
+		buffer.append(methodName);
+	}
+	
+	// parameters
+	buffer.append('(');
+	char[][] pts = getParameterTypes(methodSignature);
+	for (int i = 0; i < pts.length; i++) {
+		appendTypeSignature(pts[i], 0 , fullyQualifyTypeNames, buffer);
+		if (parameterNames != null) {
+			buffer.append(' ');
+			buffer.append(parameterNames[i]);
+		}
+		if (i != pts.length - 1) {
+			buffer.append(',');
+			buffer.append(' ');
+		}
+	}
+	buffer.append(')');
+	char[] result = new char[buffer.length()];
+	buffer.getChars(0, buffer.length(), result, 0);
+	return result;
+}
+
+/**
+ * Converts the given type signature to a readable string. The signature is expected to
+ * be dot-based.
+ * 
+ * <p>
+ * For example:
+ * <pre>
+ * <code>
+ * toString({'[', 'L', 'j', 'a', 'v', 'a', '.', 'l', 'a', 'n', 'g', '.', 'S', 't', 'r', 'i', 'n', 'g', ';'}) -> {'j', 'a', 'v', 'a', '.', 'l', 'a', 'n', 'g', '.', 'S', 't', 'r', 'i', 'n', 'g', '[', ']'}
+ * toString({'I'}) -> {'i', 'n', 't'}
+ * </code>
+ * </pre>
+ * </p>
+ * <p>
+ * Note: This method assumes that a type signature containing a <code>'$'</code>
+ * is an inner type signature. While this is correct in most cases, someone could 
+ * define a non-inner type name containing a <code>'$'</code>. Handling this 
+ * correctly in all cases would have required resolving the signature, which 
+ * generally not feasible.
+ * </p>
+ *
+ * @param signature the type signature
+ * @return the string representation of the type
+ * @exception IllegalArgumentException if the signature is not syntactically
+ *   correct
+ * 
+ * @since 2.0
+ */
+public static char[] toCharArray(char[] signature) throws IllegalArgumentException {
+		int sigLength = signature.length;
+		if (sigLength == 0 || signature[0] == C_PARAM_START || signature[0] == C_GENERIC_START) {
+			return toCharArray(signature, CharOperation.NO_CHAR, null, true, true);
+		}
+		
+		StringBuffer buffer = new StringBuffer(signature.length + 10);
+		appendTypeSignature(signature, 0, true, buffer);
+		char[] result = new char[buffer.length()];
+		buffer.getChars(0, buffer.length(), result, 0);
+		return result;
+}
+
+/**
+ * Scans the given string for a type signature starting at the given
+ * index and appends it to the given buffer, and returns the index of the last
+ * character.
+ * 
+ * @param string the signature string
+ * @param start the 0-based character index of the first character
+ * @param fullyQualifyTypeNames <code>true</code> if type names should be fully
+ *   qualified, and <code>false</code> to use only simple names
+ * @param buffer the string buffer to append to
+ * @return the 0-based character index of the last character
+ * @exception IllegalArgumentException if this is not a type signature
+ * @see #scanTypeSignature(char[], int)
+ */
+private static int appendTypeSignature(char[] string, int start, boolean fullyQualifyTypeNames, StringBuffer buffer) {
+		// need a minimum 1 char
+		if (start >= string.length) {
+			throw new IllegalArgumentException();
+		}
+		char c = string[start];
+		switch (c) {
+			case C_ARRAY :
+				return appendArrayTypeSignature(string, start, fullyQualifyTypeNames, buffer);
+			case C_RESOLVED :
+			case C_UNRESOLVED :
+				return appendClassTypeSignature(string, start, fullyQualifyTypeNames, buffer);
+			case C_TYPE_VARIABLE :
+				int e = scanTypeVariableSignature(string, start);
+				buffer.append(CharOperation.subarray(string, start + 1, e));
+				return e;
+			case C_BOOLEAN :
+				buffer.append(BOOLEAN);
+				return start;
+			case C_BYTE :
+				buffer.append(BYTE);
+				return start;
+			case C_CHAR :
+				buffer.append(CHAR);
+				return start;
+			case C_DOUBLE :
+				buffer.append(DOUBLE);
+				return start;
+			case C_FLOAT :
+				buffer.append(FLOAT);
+				return start;
+			case C_INT :
+				buffer.append(INT);
+				return start;
+			case C_LONG :
+				buffer.append(LONG);
+				return start;
+			case C_SHORT :
+				buffer.append(SHORT);
+				return start;
+			case C_VOID :
+				buffer.append(VOID);
+				return start;
+			case C_CONST :
+			    buffer.append(CONST);
+			    return start;
+			default :
+				throw new IllegalArgumentException();
+		}
+}
+
+/**
+ * Scans the given string for an array type signature starting at the given
+ * index and appends it to the given buffer, and returns the index of the last
+ * character.
+ * 
+ * @param string the signature string
+ * @param start the 0-based character index of the first character
+ * @param fullyQualifyTypeNames <code>true</code> if type names should be fully
+ *   qualified, and <code>false</code> to use only simple names
+ * @return the 0-based character index of the last character
+ * @exception IllegalArgumentException if this is not an array type signature
+ * @see #scanArrayTypeSignature(char[], int)
+ */
+private static int appendArrayTypeSignature(char[] string, int start, boolean fullyQualifyTypeNames, StringBuffer buffer) {
+	// need a minimum 2 char
+	if (start >= string.length - 1) {
+		throw new IllegalArgumentException();
+	}
+	char c = string[start];
+	if (c != C_ARRAY) { //$NON-NLS-1$
+		throw new IllegalArgumentException();
+	}
+	int e = appendTypeSignature(string, start + 1, fullyQualifyTypeNames, buffer);
+	buffer.append('[');
+	buffer.append(']');
+	return e;
+}
+
+/**
+ * Scans the given string for a class type signature starting at the given
+ * index and appends it to the given buffer, and returns the index of the last
+ * character.
+ * 
+ * @param string the signature string
+ * @param start the 0-based character index of the first character
+ * @param fullyQualifyTypeNames <code>true</code> if type names should be fully
+ *   qualified, and <code>false</code> to use only simple names
+ * @param buffer the string buffer to append to
+ * @return the 0-based character index of the last character
+ * @exception IllegalArgumentException if this is not a class type signature
+ * @see #scanClassTypeSignature(char[], int)
+ */
+private static int appendClassTypeSignature(char[] string, int start, boolean fullyQualifyTypeNames, StringBuffer buffer) {
+	// need a minimum 3 chars "Lx;"
+	if (start >= string.length - 2) { 
+		throw new IllegalArgumentException();
+	}
+	// must start in "L" or "Q"
+	char c = string[start];
+	if (c != C_RESOLVED && c != C_UNRESOLVED) {
+		throw new IllegalArgumentException();
+	}
+	boolean resolved = (c == C_RESOLVED);
+	boolean removePackageQualifiers = !fullyQualifyTypeNames;
+	if (!resolved) {
+		// keep everything in an unresolved name
+		removePackageQualifiers = false;
+	}
+	int p = start + 1;
+	int checkpoint = buffer.length();
+	while (true) {
+		if (p >= string.length) {
+			throw new IllegalArgumentException();
+		}
+		c = string[p];
+		switch(c) {
+			case C_SEMICOLON :
+				// all done
+				return p;
+			case C_GENERIC_START :
+				int e = appendTypeArgumentSignatures(string, p, fullyQualifyTypeNames, buffer);
+				// once we hit type arguments there are no more package prefixes
+				removePackageQualifiers = false;
+				p = e;
+				break;
+			case C_DOT :
+				if (removePackageQualifiers) {
+					// erase package prefix
+					buffer.setLength(checkpoint);
+				} else {
+					buffer.append('.');
+				}
+				break;
+			 case '/' :
+				if (removePackageQualifiers) {
+					// erase package prefix
+					buffer.setLength(checkpoint);
+				} else {
+					buffer.append('/');
+				}
+				break;
+			 case C_DOLLAR :
+			 	if (resolved) {
+					// once we hit "$" there are no more package prefixes
+					removePackageQualifiers = false;
+					/**
+					 * Convert '$' in resolved type signatures into '.'.
+					 * NOTE: This assumes that the type signature is an inner type
+					 * signature. This is true in most cases, but someone can define a
+					 * non-inner type name containing a '$'.
+					 */
+					buffer.append('.');
+			 	}
+			 	break;
+			 default :
+				buffer.append(c);
+		}
+		p++;
+	}
+}
+
+/**
+ * Scans the given string for a list of type arguments signature starting at the
+ * given index and appends it to the given buffer, and returns the index of the
+ * last character.
+ * 
+ * @param string the signature string
+ * @param start the 0-based character index of the first character
+ * @param fullyQualifyTypeNames <code>true</code> if type names should be fully
+ *   qualified, and <code>false</code> to use only simple names
+ * @param buffer the string buffer to append to
+ * @return the 0-based character index of the last character
+ * @exception IllegalArgumentException if this is not a list of type argument
+ * signatures
+ * @see #scanTypeArgumentSignatures(char[], int)
+ */
+private static int appendTypeArgumentSignatures(char[] string, int start, boolean fullyQualifyTypeNames, StringBuffer buffer) {
+	// need a minimum 2 char "<>"
+	if (start >= string.length - 1) {
+		throw new IllegalArgumentException();
+	}
+	char c = string[start];
+	if (c != C_GENERIC_START) {
+		throw new IllegalArgumentException();
+	}
+	buffer.append('<');
+	int p = start + 1;
+	int count = 0;
+	while (true) {
+		if (p >= string.length) {
+			throw new IllegalArgumentException();
+		}
+		c = string[p];
+		if (c == C_GENERIC_END) {
+			buffer.append('>');
+			return p;
+		}
+		if (count != 0) {
+			buffer.append(',');
+		}
+		int e = appendTypeArgumentSignature(string, p, fullyQualifyTypeNames, buffer);
+		count++;
+		p = e + 1;
+	}
+}
+
+/**
+ * Scans the given string for a type argument signature starting at the given
+ * index and appends it to the given buffer, and returns the index of the last
+ * character.
+ * 
+ * @param string the signature string
+ * @param start the 0-based character index of the first character
+ * @param fullyQualifyTypeNames <code>true</code> if type names should be fully
+ *   qualified, and <code>false</code> to use only simple names
+ * @param buffer the string buffer to append to
+ * @return the 0-based character index of the last character
+ * @exception IllegalArgumentException if this is not a type argument signature
+ * @see #scanTypeArgumentSignature(char[], int)
+ */
+private static int appendTypeArgumentSignature(char[] string, int start, boolean fullyQualifyTypeNames, StringBuffer buffer) {
+	// need a minimum 1 char
+	if (start >= string.length) {
+		throw new IllegalArgumentException();
+	}
+	char c = string[start];
+	switch(c) {
+		case C_STAR :
+			buffer.append('?');
+			return start;
+		case '+' :
+			buffer.append("? extends "); //$NON-NLS-1$
+			return appendTypeSignature(string, start + 1, fullyQualifyTypeNames, buffer);
+		case '-' :
+			buffer.append("? super "); //$NON-NLS-1$
+			return appendTypeSignature(string, start + 1, fullyQualifyTypeNames, buffer);
+		default :
+			return appendTypeSignature(string, start, fullyQualifyTypeNames, buffer);
+	}
+}
+
+/**
+ * Converts the given array of qualified name segments to a qualified name.
+ * <p>
+ * For example:
+ * <pre>
+ * <code>
+ * toQualifiedName({{'j', 'a', 'v', 'a'}, {'l', 'a', 'n', 'g'}, {'O', 'b', 'j', 'e', 'c', 't'}}) -> {'j', 'a', 'v', 'a', '.', 'l', 'a', 'n', 'g', '.', 'O', 'b', 'j', 'e', 'c', 't'}
+ * toQualifiedName({{'O', 'b', 'j', 'e', 'c', 't'}}) -> {'O', 'b', 'j', 'e', 'c', 't'}
+ * toQualifiedName({{}}) -> {}
+ * </code>
+ * </pre>
+ * </p>
+ *
+ * @param segments the list of name segments, possibly empty
+ * @return the dot-separated qualified name, or the empty string
+ * 
+ * @since 2.0
+ */
+public static char[] toQualifiedName(char[][] segments) {
+	int length = segments.length;
+	if (length == 0) return CharOperation.NO_CHAR;
+	if (length == 1) return segments[0];
+	
+	int resultLength = 0;
+	for (int i = 0; i < length; i++) {
+		resultLength += segments[i].length+1;
+	}
+	resultLength--;
+	char[] result = new char[resultLength];
+	int index = 0;
+	for (int i = 0; i < length; i++) {
+		char[] segment = segments[i];
+		int segmentLength = segment.length;
+		System.arraycopy(segment, 0, result, index, segmentLength);
+		index += segmentLength;
+		if (i != length-1) {
+			result[index++] = C_DOT;
+		}
+	}
+	return result;
+}
+/**
+ * Converts the given array of qualified name segments to a qualified name.
+ * <p>
+ * For example:
+ * <pre>
+ * <code>
+ * toQualifiedName(new String[] {"java", "lang", "Object"}) -> "java.lang.Object"
+ * toQualifiedName(new String[] {"Object"}) -> "Object"
+ * toQualifiedName(new String[0]) -> ""
+ * </code>
+ * </pre>
+ * </p>
+ *
+ * @param segments the list of name segments, possibly empty
+ * @return the dot-separated qualified name, or the empty string
+ */
+public static String toQualifiedName(String[] segments) {
+	int length = segments.length;
+	char[][] charArrays = new char[length][];
+	for (int i = 0; i < length; i++) {
+		charArrays[i] = segments[i].toCharArray();
+	}
+	return new String(toQualifiedName(charArrays));
+}
+/**
+ * Converts the given type signature to a readable string. The signature is expected to
+ * be dot-based.
+ * 
+ * <p>
+ * For example:
+ * <pre>
+ * <code>
+ * toString("[Ljava.lang.String;") -> "java.lang.String[]"
+ * toString("I") -> "int"
+ * </code>
+ * </pre>
+ * </p>
+ * <p>
+ * Note: This method assumes that a type signature containing a <code>'$'</code>
+ * is an inner type signature. While this is correct in most cases, someone could 
+ * define a non-inner type name containing a <code>'$'</code>. Handling this 
+ * correctly in all cases would have required resolving the signature, which 
+ * generally not feasible.
+ * </p>
+ *
+ * @param signature the type signature
+ * @return the string representation of the type
+ * @exception IllegalArgumentException if the signature is not syntactically
+ *   correct
+ */
+public static String toString(String signature) throws IllegalArgumentException {
+	return new String(toCharArray(signature.toCharArray()));
+}
+/**
+ * Converts the given method signature to a readable string. The method signature is expected to
+ * be dot-based.
+ * 
+ * @param methodSignature the method signature to convert
+ * @param methodName the name of the method to insert in the result, or 
+ *   <code>null</code> if no method name is to be included
+ * @param parameterNames the parameter names to insert in the result, or 
+ *   <code>null</code> if no parameter names are to be included; if supplied,
+ *   the number of parameter names must match that of the method signature
+ * @param fullyQualifyTypeNames <code>true</code> if type names should be fully
+ *   qualified, and <code>false</code> to use only simple names
+ * @param includeReturnType <code>true</code> if the return type is to be
+ *   included
+ * @see #toCharArray(char[], char[], char[][], boolean, boolean)
+ * @return the string representation of the method signature
+ */
+public static String toString(String methodSignature, String methodName, String[] parameterNames, boolean fullyQualifyTypeNames, boolean includeReturnType) {
+	char[][] params;
+	if (parameterNames == null) {
+		params = null;
+	} else {
+		int paramLength = parameterNames.length;
+		params = new char[paramLength][];
+		for (int i = 0; i < paramLength; i++) {
+			params[i] = parameterNames[i].toCharArray();
+		}
+	}
+	return new String(toCharArray(methodSignature.toCharArray(), methodName == null ? null : methodName.toCharArray(), params, fullyQualifyTypeNames, includeReturnType));
+}
+
+}
Index: browser/org/eclipse/cdt/core/browser/TypeUtil.java
===================================================================
RCS file: browser/org/eclipse/cdt/core/browser/TypeUtil.java
diff -N browser/org/eclipse/cdt/core/browser/TypeUtil.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ browser/org/eclipse/cdt/core/browser/TypeUtil.java	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,282 @@
+/*
+ * Created on Jul 5, 2004
+ *
+ * TODO To change the template for this generated file go to
+ * Window - Preferences - Java - Code Style - Code Templates
+ */
+package org.eclipse.cdt.core.browser;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.cdt.core.browser.typehierarchy.ITypeHierarchy;
+import org.eclipse.cdt.core.model.CModelException;
+import org.eclipse.cdt.core.model.Flags;
+import org.eclipse.cdt.core.model.ICElement;
+import org.eclipse.cdt.core.model.ICElementVisitor;
+import org.eclipse.cdt.core.model.ICProject;
+import org.eclipse.cdt.core.model.IMember;
+import org.eclipse.cdt.core.model.IMethodDeclaration;
+import org.eclipse.cdt.core.model.IParent;
+import org.eclipse.cdt.core.model.IStructure;
+import org.eclipse.cdt.core.model.ITranslationUnit;
+import org.eclipse.cdt.core.parser.ast.ASTAccessVisibility;
+import org.eclipse.cdt.internal.core.browser.cache.ITypeCache;
+import org.eclipse.cdt.internal.core.browser.cache.TypeCacheManager;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.NullProgressMonitor;
+
+/**
+ * @author CWiebe
+ *
+ * TODO To change the template for this generated type comment go to
+ * Window - Preferences - Java - Code Style - Code Templates
+ */
+public class TypeUtil {
+
+    public static ICElement getDeclaringType(ICElement type) {
+    	ICElement parentElement = type.getParent();
+    	if (parentElement != null && isClassOrStruct(parentElement)) {
+    	    return parentElement;
+    	}
+
+    	if (isClassOrStruct(type)) {
+        	while (parentElement != null) {
+        	    if (isClassOrStruct(parentElement)) {
+        			return parentElement;
+        		} else if (parentElement instanceof IMember) {
+       				parentElement = parentElement.getParent();
+       			} else {
+       				return null;
+        		}
+        	}
+        }
+
+    	return null;
+    }
+    
+    public static boolean isClassOrStruct(ICElement type) {
+        int kind = type.getElementType();
+		// case ICElement.C_TEMPLATE_CLASS:
+		// case ICElement.C_TEMPLATE_STRUCT:
+        return (kind == ICElement.C_CLASS || kind == ICElement.C_STRUCT);
+    }
+
+    public static boolean isClass(ICElement type) {
+        return (type.getElementType() == ICElement.C_CLASS);
+    }
+
+    public static boolean isNamespace(ICElement type) {
+        return (type.getElementType() == ICElement.C_NAMESPACE);
+    }
+
+    public static ICElement[] getTypes(ICElement elem) {
+        final List typeList = new ArrayList(3);
+        try {
+            elem.accept(new ICElementVisitor() {
+                public boolean visit(ICElement element) throws CoreException {
+                    // TODO Auto-generated method stub
+                    if (element instanceof IStructure) {
+                        typeList.add(element);
+                    }
+                    return false;
+                }});
+        } catch (CoreException e) {
+        }
+        return (ICElement[])typeList.toArray(new ICElement[typeList.size()]);
+	}
+	
+    public static IQualifiedTypeName getFullyQualifiedName(ICElement type) {
+		String name = type.getElementName();
+		IQualifiedTypeName qualifiedName = new QualifiedTypeName(name);
+		ICElement parent = type.getParent();
+		while (parent != null && (isNamespace(parent) || isClass(parent))) {
+			qualifiedName = new QualifiedTypeName(parent.getElementName()).append(qualifiedName);
+		    parent = parent.getParent();
+		}
+	    return qualifiedName;
+	}
+    
+    public static ITypeInfo getTypeForElement(ICElement elem, IProgressMonitor monitor) {
+        if (elem != null) {
+			ICProject cProject = elem.getCProject();
+			IQualifiedTypeName qualifiedName = getFullyQualifiedName(elem);
+			if (qualifiedName != null) {
+				final ITypeSearchScope fScope = new TypeSearchScope(true);
+				if (!AllTypesCache.isCacheUpToDate(fScope)) {
+					AllTypesCache.updateCache(fScope, monitor);
+				}
+					
+				ITypeCache cache = TypeCacheManager.getInstance().getCache(cProject.getProject());
+			    ITypeInfo info = cache.getType(elem.getElementType(), qualifiedName);
+			    if (info != null) {
+					ITypeReference ref = info.getResolvedReference();
+					if (ref == null) {
+						ref = AllTypesCache.resolveTypeLocation(info, monitor);
+					}
+					return info;
+			    }
+			}
+        }
+		return null;
+    }
+
+    public static ITypeInfo getTypeForElement(ICElement elem) {
+        return getTypeForElement(elem, new NullProgressMonitor());
+    }
+    
+    public static ICElement getElementForType(ITypeInfo type, IProgressMonitor monitor) {
+		final ITypeSearchScope fScope = new TypeSearchScope(true);
+		if (!AllTypesCache.isCacheUpToDate(fScope)) {
+			AllTypesCache.updateCache(fScope, monitor);
+		}
+		ITypeReference ref = type.getResolvedReference();
+		if (ref == null) {
+			ref = AllTypesCache.resolveTypeLocation(type, monitor);
+		}
+		if (ref != null) {
+			ICElement[] elems = ref.getCElements();
+			if (elems != null && elems.length > 0) {
+				if (elems.length == 1)
+					return elems[0];
+
+				for (int i = 0; i < elems.length; ++i) {
+					ICElement elem = elems[i];
+					if (elem.getElementType() == type.getCElementType() && elem.getElementName().equals(type.getName())) {
+						//TODO should check fully qualified name
+						return elem;
+					}
+				}
+			}
+		}
+		return null;
+    }
+    public static ICElement getElementForType(ITypeInfo type) {
+        return getElementForType(type, new NullProgressMonitor());
+    }
+
+    public static IMethodDeclaration[] getMethods(ICElement elem) {
+	    if (elem instanceof IStructure) {
+	        try {
+	            List list = ((IParent)elem).getChildrenOfType(ICElement.C_METHOD_DECLARATION);
+	            if (list != null && !list.isEmpty()) {
+	                return (IMethodDeclaration[]) list.toArray(new IMethodDeclaration[list.size()]);
+	            }
+	        } catch (CModelException e) {
+	        }
+	    }
+	    return null;
+	}
+
+    public static ICElement[] getFields(ICElement elem) {
+	    if (elem instanceof IStructure) {
+	        try {
+	            List list = ((IParent)elem).getChildrenOfType(ICElement.C_FIELD);
+	            if (list != null && !list.isEmpty()) {
+	                return (ICElement[]) list.toArray(new ICElement[list.size()]);
+	            }
+	        } catch (CModelException e) {
+	        }
+	    }
+	    return null;
+	}
+    
+    
+	/**
+	 * Finds a method by name.
+	 * This searches for a method with a name and signature. Parameter types are only
+	 * compared by the simple name, no resolving for the fully qualified type name is done.
+	 * Constructors are only compared by parameters, not the name.
+	 * @param name The name of the method to find
+	 * @param paramTypes The type signatures of the parameters e.g. <code>{"QString;","I"}</code>
+	 * @param isConstructor If the method is a constructor
+	 * @param methods The methods to search in
+	 * @return The found method or <code>null</code>, if nothing found
+	 */
+//  TODO move methods to CModelUtil
+	public static IMethodDeclaration findMethod(String name, String[] paramTypes, boolean isConstructor, boolean isDestructor, IMethodDeclaration[] methods) throws CModelException {
+		for (int i= methods.length - 1; i >= 0; i--) {
+			if (isSameMethodSignature(name, paramTypes, isConstructor, isDestructor, methods[i])) {
+				return methods[i];
+			}
+		}
+		return null;
+	}
+   
+	/**
+	 * Tests if a method equals to the given signature.
+	 * Parameter types are only compared by the simple name, no resolving for
+	 * the fully qualified type name is done. Constructors are only compared by
+	 * parameters, not the name.
+	 * @param name Name of the method
+	 * @param paramTypes The type signatures of the parameters e.g. <code>{"QString;","I"}</code>
+	 * @param isConstructor Specifies if the method is a constructor
+	 * @return Returns <code>true</code> if the method has the given name and parameter types and constructor state.
+	 */
+//TODO move methods to CModelUtil
+	public static boolean isSameMethodSignature(String name, String[] paramTypes, boolean isConstructor, boolean isDestructor, IMethodDeclaration curr) throws CModelException {
+		if (isConstructor || isDestructor || name.equals(curr.getElementName())) {
+			if ((isConstructor == curr.isConstructor()) && (isDestructor == curr.isDestructor())) {
+				String[] currParamTypes= curr.getParameterTypes();
+				if (paramTypes.length == currParamTypes.length) {
+					for (int i= 0; i < paramTypes.length; i++) {
+						String t1= Signature.getSimpleName(Signature.toString(paramTypes[i]));
+						String t2= Signature.getSimpleName(Signature.toString(currParamTypes[i]));
+						if (!t1.equals(t2)) {
+							return false;
+						}
+					}
+					return true;
+				}
+			}
+		}
+		return false;
+	}
+	
+	/**
+	 * Finds a method in a type.
+	 * This searches for a method with the same name and signature. Parameter types are only
+	 * compared by the simple name, no resolving for the fully qualified type name is done.
+	 * Constructors are only compared by parameters, not the name.
+	 * @param name The name of the method to find
+	 * @param paramTypes The type signatures of the parameters e.g. <code>{"QString;","I"}</code>
+	 * @param isConstructor If the method is a constructor
+	 * @return The first found method or <code>null</code>, if nothing found
+	 */
+//	TODO move methods to CModelUtil
+	public static IMethodDeclaration findMethod(String name, String[] paramTypes, boolean isConstructor, boolean isDestructor, ICElement type) throws CModelException {
+		return findMethod(name, paramTypes, isConstructor, isDestructor, getMethods(type));
+	}
+
+	/**
+	 * Finds a method declararion in a type's hierarchy. The search is top down, so this
+	 * returns the first declaration of the method in the hierarchy.
+	 * This searches for a method with a name and signature. Parameter types are only
+	 * compared by the simple name, no resolving for the fully qualified type name is done.
+	 * Constructors are only compared by parameters, not the name.
+	 * @param type Searches in this type's supertypes.
+	 * @param name The name of the method to find
+	 * @param paramTypes The type signatures of the parameters e.g. <code>{"QString;","I"}</code>
+	 * @param isConstructor If the method is a constructor
+	 * @return The first method found or null, if nothing found
+	 */
+//	TODO move methods to CModelUtil
+	public static IMethodDeclaration findMethodDeclarationInHierarchy(ITypeHierarchy hierarchy, ICElement type, String name, String[] paramTypes, boolean isConstructor, boolean isDestructor) throws CModelException {
+		ICElement[] superTypes= hierarchy.getAllSupertypes(type);
+		for (int i= superTypes.length - 1; i >= 0; i--) {
+		    IMethodDeclaration first= findMethod(name, paramTypes, isConstructor, isDestructor, superTypes[i]);
+			if (first != null && first.getVisibility() != ASTAccessVisibility.PRIVATE) {
+				// the order getAllSupertypes does make assumptions of the order of inner elements -> search recursivly
+			    IMethodDeclaration res= findMethodDeclarationInHierarchy(hierarchy, TypeUtil.getDeclaringType(first), name, paramTypes, isConstructor, isDestructor);
+				if (res != null) {
+					return res;
+				}
+				return first;
+			}
+		}
+		return null;
+	}
+	
+}
Index: browser/org/eclipse/cdt/core/browser/typehierarchy/ChangeCollector.java
===================================================================
RCS file: browser/org/eclipse/cdt/core/browser/typehierarchy/ChangeCollector.java
diff -N browser/org/eclipse/cdt/core/browser/typehierarchy/ChangeCollector.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ browser/org/eclipse/cdt/core/browser/typehierarchy/ChangeCollector.java	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,451 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.core.browser.typehierarchy;
+
+import java.util.*;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import org.eclipse.cdt.core.browser.TypeUtil;
+import org.eclipse.cdt.core.model.CModelException;
+import org.eclipse.cdt.core.model.ICElement;
+import org.eclipse.cdt.core.model.ICElementDelta;
+import org.eclipse.cdt.core.model.IMember;
+import org.eclipse.cdt.core.model.IParent;
+import org.eclipse.cdt.core.model.ITranslationUnit;
+import org.eclipse.cdt.internal.core.model.CElement;
+
+/*
+ * Collects changes (reported through fine-grained deltas) that can affect a type hierarchy.
+ */
+public class ChangeCollector {
+	
+	/*
+	 * A table from ICElements to TypeDeltas
+	 */
+	HashMap changes = new HashMap();
+	
+	TypeHierarchy hierarchy;
+	
+	public ChangeCollector(TypeHierarchy hierarchy) {
+		this.hierarchy = hierarchy;
+	}
+	
+	/*
+	 * Adds the children of the given delta to the list of changes.
+	 */
+	private void addAffectedChildren(ICElementDelta delta) throws CModelException {
+//		ICElementDelta[] children = delta.getAffectedChildren();
+//		for (int i = 0, length = children.length; i < length; i++) {
+//			ICElementDelta child = children[i];
+//			ICElement childElement = child.getElement();
+//			switch (childElement.getElementType()) {
+//				case ICElement.IMPORT_CONTAINER:
+//					addChange((IImportContainer)childElement, child);
+//					break;
+//				case ICElement.IMPORT_DECLARATION:
+//					addChange((IImportDeclaration)childElement, child);
+//					break;
+//				case ICElement.TYPE:
+//					addChange((ICElement)childElement, child);
+//					break;
+//				case ICElement.INITIALIZER:
+//				case ICElement.FIELD:
+//				case ICElement.METHOD:
+//					addChange((IMember)childElement, child);
+//					break;
+//			}
+//		}
+	}
+	
+	/*
+	 * Adds the given delta on a compilation unit to the list of changes.
+	 */
+	public void addChange(ITranslationUnit cu, ICElementDelta newDelta) throws CModelException {
+//		int newKind = newDelta.getKind();
+//		switch (newKind) {
+//			case ICElementDelta.ADDED:
+//				ArrayList allTypes = new ArrayList();
+//				getAllTypesFromElement(cu, allTypes);
+//				for (int i = 0, length = allTypes.size(); i < length; i++) {
+//					ICElement type = (ICElement)allTypes.get(i);
+//					addTypeAddition(type, (SimpleDelta)this.changes.get(type));
+//				}
+//				break;
+//			case ICElementDelta.REMOVED:
+//				allTypes = new ArrayList();
+//				getAllTypesFromHierarchy((JavaElement)cu, allTypes);
+//				for (int i = 0, length = allTypes.size(); i < length; i++) {
+//					ICElement type = (ICElement)allTypes.get(i);
+//					addTypeRemoval(type, (SimpleDelta)this.changes.get(type));
+//				}
+//				break;
+//			case ICElementDelta.CHANGED:
+//				addAffectedChildren(newDelta);
+//				break;
+//		}
+	}
+	
+/*	private void addChange(IImportContainer importContainer, ICElementDelta newDelta) throws CModelException {
+		int newKind = newDelta.getKind();
+		if (newKind == ICElementDelta.CHANGED) {
+			addAffectedChildren(newDelta);
+			return;
+		}
+		SimpleDelta existingDelta = (SimpleDelta)this.changes.get(importContainer);
+		if (existingDelta != null) {
+			switch (newKind) {
+				case ICElementDelta.ADDED:
+					if (existingDelta.getKind() == ICElementDelta.REMOVED) {
+						// REMOVED then ADDED
+						this.changes.remove(importContainer);
+					}
+					break;
+				case ICElementDelta.REMOVED:
+					if (existingDelta.getKind() == ICElementDelta.ADDED) {
+						// ADDED then REMOVED
+						this.changes.remove(importContainer);
+					}
+					break;
+					// CHANGED handled above
+			}
+		} else {
+			SimpleDelta delta = new SimpleDelta();
+			switch (newKind) {
+				case ICElementDelta.ADDED:
+					delta.added();
+					break;
+				case ICElementDelta.REMOVED:
+					delta.removed();
+					break;
+			}
+			this.changes.put(importContainer, delta);
+		}
+	}
+	
+	private void addChange(IImportDeclaration importDecl, ICElementDelta newDelta) {
+		SimpleDelta existingDelta = (SimpleDelta)this.changes.get(importDecl);
+		int newKind = newDelta.getKind();
+		if (existingDelta != null) {
+			switch (newKind) {
+				case ICElementDelta.ADDED:
+					if (existingDelta.getKind() == ICElementDelta.REMOVED) {
+						// REMOVED then ADDED
+						this.changes.remove(importDecl);
+					}
+					break;
+				case ICElementDelta.REMOVED:
+					if (existingDelta.getKind() == ICElementDelta.ADDED) {
+						// ADDED then REMOVED
+						this.changes.remove(importDecl);
+					}
+					break;
+				// CHANGED cannot happen for import declaration
+			}
+		} else {
+			SimpleDelta delta = new SimpleDelta();
+			switch (newKind) {
+				case ICElementDelta.ADDED:
+					delta.added();
+					break;
+				case ICElementDelta.REMOVED:
+					delta.removed();
+					break;
+			}
+			this.changes.put(importDecl, delta);
+		}
+	}
+*/
+	
+	/*
+	 * Adds a change for the given member (a method, a field or an initializer) and the types it defines.
+	 */
+	private void addChange(IMember member, ICElementDelta newDelta) throws CModelException {
+//		int newKind = newDelta.getKind();
+//		switch (newKind) {
+//			case ICElementDelta.ADDED:
+//				ArrayList allTypes = new ArrayList();
+//				getAllTypesFromElement(member, allTypes);
+//				for (int i = 0, length = allTypes.size(); i < length; i++) {
+//					ICElement innerType = (ICElement)allTypes.get(i);
+//					addTypeAddition(innerType, (SimpleDelta)this.changes.get(innerType));
+//				}
+//				break;
+//			case ICElementDelta.REMOVED:
+//				allTypes = new ArrayList();
+//				getAllTypesFromHierarchy((JavaElement)member, allTypes);
+//				for (int i = 0, length = allTypes.size(); i < length; i++) {
+//					ICElement type = (ICElement)allTypes.get(i);
+//					addTypeRemoval(type, (SimpleDelta)this.changes.get(type));
+//				}
+//				break;
+//			case ICElementDelta.CHANGED:
+//				addAffectedChildren(newDelta);
+//				break;
+//		}
+	}
+	
+	/*
+	 * Adds a change for the given type and the types it defines.
+	 */
+	private void addChange(ICElement type, ICElementDelta newDelta) throws CModelException {
+//		 int newKind = newDelta.getKind();
+//		SimpleDelta existingDelta = (SimpleDelta)this.changes.get(type);
+//		switch (newKind) {
+//			case ICElementDelta.ADDED:
+//				addTypeAddition(type, existingDelta);
+//				ArrayList allTypes = new ArrayList();
+//				getAllTypesFromElement(type, allTypes);
+//				for (int i = 0, length = allTypes.size(); i < length; i++) {
+//					ICElement innerType = (ICElement)allTypes.get(i);
+//					addTypeAddition(innerType, (SimpleDelta)this.changes.get(innerType));
+//				}
+//				break;
+//			case ICElementDelta.REMOVED:
+//				addTypeRemoval(type, existingDelta);
+//				allTypes = new ArrayList();
+//				getAllTypesFromHierarchy((JavaElement)type, allTypes);
+//				for (int i = 0, length = allTypes.size(); i < length; i++) {
+//					ICElement innerType = (ICElement)allTypes.get(i);
+//					addTypeRemoval(innerType, (SimpleDelta)this.changes.get(innerType));
+//				}
+//				break;
+//			case ICElementDelta.CHANGED:
+//				addTypeChange(type, newDelta.getFlags(), existingDelta);
+//				addAffectedChildren(newDelta);
+//				break;
+//		}
+	}
+
+/*	private void addTypeAddition(ICElement type, SimpleDelta existingDelta) throws CModelException {
+		if (existingDelta != null) {
+			switch (existingDelta.getKind()) {
+				case ICElementDelta.REMOVED:
+					// REMOVED then ADDED
+					boolean hasChange = false;
+					if (hasSuperTypeChange(type)) {
+						existingDelta.superTypes();
+						hasChange = true;
+					} 
+					if (hasVisibilityChange(type)) {
+						existingDelta.modifiers();
+						hasChange = true;
+					}
+					if (!hasChange) {
+						this.changes.remove(type);
+					}
+					break;
+					// CHANGED then ADDED
+					// or ADDED then ADDED: should not happen
+			}
+		} else {
+			// check whether the type addition affects the hierarchy
+			String typeName = type.getElementName();
+			if (this.hierarchy.hasSupertype(typeName) 
+					|| this.hierarchy.subtypesIncludeSupertypeOf(type) 
+					|| this.hierarchy.missingTypes.contains(typeName)) {
+				SimpleDelta delta = new SimpleDelta();
+				delta.added();
+				this.changes.put(type, delta);
+			}
+		}
+	}
+*/	
+/*	private void addTypeChange(ICElement type, int newFlags, SimpleDelta existingDelta) throws CModelException {
+		if (existingDelta != null) {
+			switch (existingDelta.getKind()) {
+				case ICElementDelta.CHANGED:
+					// CHANGED then CHANGED
+					int existingFlags = existingDelta.getFlags();
+					boolean hasChange = false;
+					if ((existingFlags & ICElementDelta.F_SUPER_TYPES) != 0
+							&& hasSuperTypeChange(type)) {
+						existingDelta.superTypes();
+						hasChange = true;
+					} 
+					if ((existingFlags & ICElementDelta.F_MODIFIERS) != 0
+							&& hasVisibilityChange(type)) {
+						existingDelta.modifiers();
+						hasChange = true;
+					}
+					if (!hasChange) {
+						// super types and visibility are back to the ones in the existing hierarchy
+						this.changes.remove(type);
+					}
+					break;
+					// ADDED then CHANGED: leave it as ADDED
+					// REMOVED then CHANGED: should not happen
+			}
+		} else {
+			// check whether the type change affects the hierarchy
+			SimpleDelta typeDelta = null;
+			if ((newFlags & ICElementDelta.F_SUPER_TYPES) != 0 
+					&& this.hierarchy.includesTypeOrSupertype(type)) {
+				typeDelta = new SimpleDelta();
+				typeDelta.superTypes();
+			}
+			if ((newFlags & ICElementDelta.F_MODIFIERS) != 0
+					&& this.hierarchy.hasSupertype(type.getElementName())) {
+				if (typeDelta == null) {
+					typeDelta = new SimpleDelta();
+				}
+				typeDelta.modifiers();
+			}
+			if (typeDelta != null) {
+				this.changes.put(type, typeDelta);
+			}
+		}
+	}
+*/
+/*	private void addTypeRemoval(ICElement type, SimpleDelta existingDelta) {
+		if (existingDelta != null) {
+			switch (existingDelta.getKind()) {
+				case ICElementDelta.ADDED:
+					// ADDED then REMOVED
+					this.changes.remove(type);
+					break;
+				case ICElementDelta.CHANGED:
+					// CHANGED then REMOVED
+					existingDelta.removed();
+					break;
+					// REMOVED then REMOVED: should not happen
+			}
+		} else {
+			// check whether the type removal affects the hierarchy
+			if (this.hierarchy.contains(type)) {
+				SimpleDelta typeDelta = new SimpleDelta();
+				typeDelta.removed();
+				this.changes.put(type, typeDelta);
+			}
+		}
+	}
+*/	
+	/*
+	 * Returns all types defined in the given element excluding the given element.
+	 */
+	private void getAllTypesFromElement(ICElement element, ArrayList allTypes) throws CModelException {
+		switch (element.getElementType()) {
+			case ICElement.C_UNIT:
+				ICElement[] types = TypeUtil.getTypes((ITranslationUnit)element);
+				for (int i = 0, length = types.length; i < length; i++) {
+					ICElement type = types[i];
+					allTypes.add(type);
+					getAllTypesFromElement(type, allTypes);
+				}
+				break;
+			case ICElement.C_CLASS:
+			case ICElement.C_STRUCT:
+//				types = ((ICElement)element).getTypes();
+			    types = TypeUtil.getTypes((ICElement)element);
+				for (int i = 0, length = types.length; i < length; i++) {
+					ICElement type = types[i];
+					allTypes.add(type);
+					getAllTypesFromElement(type, allTypes);
+				}
+				break;
+//			case ICElement.INITIALIZER:
+//			case ICElement.FIELD:
+			case ICElement.C_METHOD:
+			    if (element instanceof IParent) {
+					ICElement[] children = ((IParent)element).getChildren();
+					for (int i = 0, length = children.length; i < length; i++) {
+						ICElement type = (ICElement)children[i];
+						allTypes.add(type);
+						getAllTypesFromElement(type, allTypes);
+					}
+			    }
+				break;
+		}
+	}
+	
+	/*
+	 * Returns all types in the existing hierarchy that have the given element as a parent.
+	 */
+	private void getAllTypesFromHierarchy(CElement element, ArrayList allTypes) {
+		switch (element.getElementType()) {
+			case ICElement.C_UNIT:
+				ArrayList types = (ArrayList)this.hierarchy.files.get(element);
+				if (types != null) {
+					allTypes.addAll(types);
+				}
+				break;
+			case ICElement.C_CLASS:
+			case ICElement.C_STRUCT:
+//			case ICElement.INITIALIZER:
+//			case ICElement.FIELD:
+			case ICElement.C_METHOD:
+				types = (ArrayList)this.hierarchy.files.get(((IMember)element).getTranslationUnit());
+				if (types != null) {
+					for (int i = 0, length = types.size(); i < length; i++) {
+						ICElement type = (ICElement)types.get(i);
+						if (element.isAncestorOf(type)) {
+							allTypes.add(type);
+						}
+					}
+				}
+				break;
+		}
+	}
+	
+	private boolean hasSuperTypeChange(ICElement type) throws CModelException {
+//		// check super class
+//		ICElement superclass = this.hierarchy.getSuperclass(type);
+//		String existingSuperclassName = superclass == null ? null : superclass.getElementName();
+//		String newSuperclassName = type.getSuperclassName();
+//		if (existingSuperclassName != null && !existingSuperclassName.equals(newSuperclassName)) {
+//			return true;
+//		}
+//		
+//		// check super interfaces
+//		ICElement[] existingSuperInterfaces = this.hierarchy.getSuperInterfaces(type);
+//		String[] newSuperInterfaces = type.getSuperInterfaceNames();
+//		if (existingSuperInterfaces.length != newSuperInterfaces.length) {
+//			return true;
+//		}
+//		for (int i = 0, length = newSuperInterfaces.length; i < length; i++) {
+//			String superInterfaceName = newSuperInterfaces[i];
+//			if (!superInterfaceName.equals(newSuperInterfaces[i])) {
+//				return true;
+//			}
+//		}
+		
+		return false;
+	}
+	
+	private boolean hasVisibilityChange(ICElement type) throws CModelException {
+//		int existingFlags = this.hierarchy.getCachedFlags(type);
+//		int newFlags = type.getFlags();
+//		return existingFlags != newFlags;
+	    return false;
+	}
+
+	/*
+	 * Whether the hierarchy needs refresh according to the changes collected so far.
+	 */
+	public boolean needsRefresh() {
+		return changes.size() != 0;
+	}
+	
+	public String toString() {
+		StringBuffer buffer = new StringBuffer();
+		Iterator iterator = this.changes.entrySet().iterator();
+		while (iterator.hasNext()) {
+			Map.Entry entry = (Map.Entry)iterator.next();
+			buffer.append(((CElement)entry.getKey()).toDebugString());
+			buffer.append(entry.getValue());
+			if (iterator.hasNext()) {
+				buffer.append('\n');
+			}
+		}
+		return buffer.toString();
+	}
+}
Index: browser/org/eclipse/cdt/core/browser/typehierarchy/ITypeHierarchy.java
===================================================================
RCS file: browser/org/eclipse/cdt/core/browser/typehierarchy/ITypeHierarchy.java
diff -N browser/org/eclipse/cdt/core/browser/typehierarchy/ITypeHierarchy.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ browser/org/eclipse/cdt/core/browser/typehierarchy/ITypeHierarchy.java	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,171 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.core.browser.typehierarchy;
+
+import java.io.OutputStream;
+
+import org.eclipse.cdt.core.model.CModelException;
+import org.eclipse.cdt.core.model.ICElement;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+/**
+ * A type hierarchy provides navigations between a type and its resolved
+ * supertypes and subtypes for a specific type or for all types within a region.
+ * Supertypes may extend outside of the type hierarchy's region in which it was
+ * created such that the root of the hierarchy is always included. For example, if a type
+ * hierarchy is created for a <code>java.io.File</code>, and the region the hierarchy was
+ * created in is the package fragment <code>java.io</code>, the supertype
+ * <code>java.lang.Object</code> will still be included.
+ * <p>
+ * A type hierarchy is static and can become stale. Although consistent when 
+ * created, it does not automatically track changes in the model.
+ * As changes in the model potentially invalidate the hierarchy, change notifications
+ * are sent to registered <code>ICElementHierarchyChangedListener</code>s. Listeners should
+ * use the <code>exists</code> method to determine if the hierarchy has become completely
+ * invalid (for example, when the type or project the hierarchy was created on
+ * has been removed). To refresh a hierarchy, use the <code>refresh</code> method. 
+ * </p>
+ * <p>
+ * The type hierarchy may contain cycles due to malformed supertype declarations.
+ * Most type hierarchy queries are oblivious to cycles; the <code>getAll* </code>
+ * methods are implemented such that they are unaffected by cycles.
+ * </p>
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ */
+public interface ITypeHierarchy {
+/**
+ * Adds the given listener for changes to this type hierarchy. Listeners are
+ * notified when this type hierarchy changes and needs to be refreshed.
+ * Has no effect if an identical listener is already registered.
+ *
+ * @param listener the listener
+ */
+void addTypeHierarchyChangedListener(ITypeHierarchyChangedListener listener);
+/**
+ * Returns whether the given type is part of this hierarchy.
+ * 
+ * @param type the given type
+ * @return true if the given type is part of this hierarchy, false otherwise
+ */
+boolean contains(ICElement type);
+/**
+ * Returns whether the type and project this hierarchy was created on exist.
+ * @return true if the type and project this hierarchy was created on exist, false otherwise
+ */
+boolean exists();
+
+/**
+ * Returns all resolved subtypes (direct and indirect) of the
+ * given type, in no particular order, limited to the
+ * types in this type hierarchy's graph. An empty array
+ * is returned if there are no resolved subtypes for the
+ * given type.
+ * 
+ * @param type the given type
+ * @return all resolved subtypes (direct and indirect) of the given type
+ */
+ICElement[] getAllSubtypes(ICElement type);
+/**
+ * Returns all resolved superclasses of the
+ * given class, in bottom-up order. An empty array
+ * is returned if there are no resolved superclasses for the
+ * given class.
+ *
+ * <p>NOTE: once a type hierarchy has been created, it is more efficient to
+ * query the hierarchy for superclasses than to query a class recursively up
+ * the superclass chain. Querying an element performs a dynamic resolution,
+ * whereas the hierarchy returns a pre-computed result.
+ * 
+ * @param type the given type
+ * @return all resolved superclasses of the given class, in bottom-up order, an empty
+ * array if none.
+ */
+ICElement[] getAllSupertypes(ICElement type);
+
+/**
+ * Returns all classes in the graph which have no resolved superclass,
+ * in no particular order.
+ * 
+ * @return all classes in the graph which have no resolved superclass
+ */
+ICElement[] getRootClasses();
+
+/**
+ * Returns the direct resolved subtypes of the given type,
+ * in no particular order, limited to the types in this
+ * type hierarchy's graph.
+ * If the type is a class, this returns the resolved subclasses.
+ * If the type is an interface, this returns both the classes which implement 
+ * the interface and the interfaces which extend it.
+ * 
+ * @param type the given type
+ * @return the direct resolved subtypes of the given type limited to the types in this
+ * type hierarchy's graph
+ */
+ICElement[] getSubtypes(ICElement type);
+
+/**
+ * Returns the resolved supertypes of the given type,
+ * in no particular order, limited to the types in this
+ * type hierarchy's graph.
+ * For classes, this returns its superclass and the interfaces that the class implements.
+ * For interfaces, this returns the interfaces that the interface extends. As a consequence 
+ * <code>java.lang.Object</code> is NOT considered to be a supertype of any interface 
+ * type.
+ * 
+ * @param type the given type
+ * @return the resolved supertypes of the given type limited to the types in this
+ * type hierarchy's graph
+ */
+ICElement[] getSupertypes(ICElement type);
+/**
+ * Returns the type this hierarchy was computed for.
+ * Returns <code>null</code> if this hierarchy was computed for a region.
+ * 
+ * @return the type this hierarchy was computed for
+ */
+ICElement getType();
+/**
+ * Re-computes the type hierarchy reporting progress.
+ *
+ * @param monitor the given progress monitor
+ * @exception JavaModelException if unable to refresh the hierarchy
+ */
+void refresh(IProgressMonitor monitor) throws CModelException;
+/**
+ * Removes the given listener from this type hierarchy.
+ * Has no affect if an identical listener is not registered.
+ *
+ * @param listener the listener
+ */
+void removeTypeHierarchyChangedListener(ITypeHierarchyChangedListener listener);
+/**
+ * Stores the type hierarchy in an output stream. This stored hierarchy can be load by
+ * ICElement#loadTypeHierachy(IJavaProject, InputStream, IProgressMonitor).
+ * Listeners of this hierarchy are not stored.
+ * 
+ * Only hierarchies created by the following methods can be store:
+ * <ul>
+ * <li>ICElement#newSupertypeHierarchy(IProgressMonitor)</li>
+ * <li>ICElement#newTypeHierarchy(IJavaProject, IProgressMonitor)</li>
+ * <li>ICElement#newTypeHierarchy(IProgressMonitor)</li>
+ * </u>
+ * 
+ * @param outputStream output stream where the hierarchy will be stored
+ * @param monitor the given progress monitor
+ * @exception JavaModelException if unable to store the hierarchy in the ouput stream
+ * @see ICElement#loadTypeHierachy(java.io.InputStream, IProgressMonitor)
+ * @since 2.1
+ */
+void store(OutputStream outputStream, IProgressMonitor monitor) throws CModelException;
+}
Index: browser/org/eclipse/cdt/core/browser/typehierarchy/ITypeHierarchyChangedListener.java
===================================================================
RCS file: browser/org/eclipse/cdt/core/browser/typehierarchy/ITypeHierarchyChangedListener.java
diff -N browser/org/eclipse/cdt/core/browser/typehierarchy/ITypeHierarchyChangedListener.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ browser/org/eclipse/cdt/core/browser/typehierarchy/ITypeHierarchyChangedListener.java	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.core.browser.typehierarchy;
+
+/**
+ * A listener which gets notified when a particular type hierarchy object
+ * changes.
+ * <p>
+ * This interface may be implemented by clients.
+ * </p>
+ */
+public interface ITypeHierarchyChangedListener {
+	/**
+	 * Notifies that the given type hierarchy has changed in some way and should
+	 * be refreshed at some point to make it consistent with the current state of
+	 * the Java model.
+	 * 
+	 * @param typeHierarchy the given type hierarchy
+	 */
+	void typeHierarchyChanged(ITypeHierarchy typeHierarchy);
+}
Index: browser/org/eclipse/cdt/core/browser/typehierarchy/TypeHierarchy.java
===================================================================
RCS file: browser/org/eclipse/cdt/core/browser/typehierarchy/TypeHierarchy.java
diff -N browser/org/eclipse/cdt/core/browser/typehierarchy/TypeHierarchy.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ browser/org/eclipse/cdt/core/browser/typehierarchy/TypeHierarchy.java	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,591 @@
+/*******************************************************************************
+ * Copyright (c) 2004 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     QNX Software Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.core.browser.typehierarchy;
+
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.cdt.core.ICLogConstants;
+import org.eclipse.cdt.core.browser.AllTypesCache;
+import org.eclipse.cdt.core.browser.ITypeInfo;
+import org.eclipse.cdt.core.browser.TypeUtil;
+import org.eclipse.cdt.core.model.CModelException;
+import org.eclipse.cdt.core.model.CoreModel;
+import org.eclipse.cdt.core.model.ElementChangedEvent;
+import org.eclipse.cdt.core.model.ICElement;
+import org.eclipse.cdt.core.model.ICElementDelta;
+import org.eclipse.cdt.core.model.ICProject;
+import org.eclipse.cdt.core.model.IElementChangedListener;
+import org.eclipse.cdt.core.parser.ast.ASTAccessVisibility;
+import org.eclipse.cdt.core.search.ICSearchScope;
+import org.eclipse.cdt.internal.core.browser.cache.TypeCacheManager;
+import org.eclipse.cdt.internal.core.model.CElement;
+import org.eclipse.cdt.internal.core.model.Util;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.ISafeRunnable;
+import org.eclipse.core.runtime.Platform;
+
+public class TypeHierarchy implements ITypeHierarchy, IElementChangedListener {
+
+	public static boolean DEBUG = false;
+    
+	private static final class TypeEntry {
+		ITypeInfo type;
+		ASTAccessVisibility access;
+		TypeEntry(ITypeInfo type, ASTAccessVisibility access) {
+			this.type = type;
+			this.access = access;
+		}
+	}
+	private static final int INITIAL_SUPER_TYPES = 1;
+	private static final int INITIAL_SUB_TYPES = 1;
+	private static final ITypeInfo[] NO_TYPES = new ITypeInfo[0];
+	private ArrayList fAllTypes = new ArrayList();
+	private ArrayList fRootTypes = new ArrayList();
+	private Map fTypeToSuperTypes = new HashMap();
+	private Map fTypeToSubTypes = new HashMap();
+
+	private ITypeInfo fFocusType;
+	
+	/**
+	 * The progress monitor to report work completed too.
+	 */
+	protected IProgressMonitor fProgressMonitor = null;
+	/**
+	 * Change listeners - null if no one is listening.
+	 */
+	protected ArrayList fChangeListeners = null;
+	
+	/*
+	 * A map from Openables to ArrayLists of ITypes
+	 */
+	public Map files = null;
+	
+	/**
+	 * Whether this hierarchy should contains subtypes.
+	 */
+	protected boolean fComputeSubtypes;
+
+	/**
+	 * The scope this hierarchy should restrain itsef in.
+	 */
+	ICSearchScope fScope;
+	
+	/*
+	 * Whether this hierarchy needs refresh
+	 */
+	public boolean fNeedsRefresh = true;
+	/*
+	 * Collects changes to types
+	 */
+	protected ChangeCollector fChangeCollector;
+	
+	
+	
+	/**
+	 * Creates a TypeHierarchy on the given type.
+	 */
+	public TypeHierarchy(ITypeInfo type) {
+		fFocusType = type;
+	}
+	
+	/**
+	 * Adds the type to the collection of root classes
+	 * if the classes is not already present in the collection.
+	 */
+	public void addRootType(ITypeInfo type) {
+		if (!fRootTypes.contains(type)) {
+			fRootTypes.add(type);
+		}
+	}
+	
+	/**
+	 * Adds the given supertype to the type.
+	 */
+	public void addSuperType(ITypeInfo type, ITypeInfo superType, ASTAccessVisibility access) {
+		Collection superEntries = (Collection) fTypeToSuperTypes.get(type);
+		if (superEntries == null) {
+		    superEntries = new ArrayList(INITIAL_SUPER_TYPES);
+			fTypeToSuperTypes.put(type, superEntries);
+		}
+		Collection subTypes = (Collection) fTypeToSubTypes.get(superType);
+		if (subTypes == null) {
+			subTypes = new ArrayList(INITIAL_SUB_TYPES);
+			fTypeToSubTypes.put(superType, subTypes);
+		}
+		if (!subTypes.contains(type)) {
+			subTypes.add(type);
+		}
+		for (Iterator i = superEntries.iterator(); i.hasNext(); ) {
+			TypeEntry entry = (TypeEntry)i.next();
+			if (entry.type.equals(superType)) {
+			    // update the access
+			    entry.access = access;
+				return;	// don't add if already exists
+			}
+		}
+		TypeEntry typeEntry = new TypeEntry(superType, access);
+		superEntries.add(typeEntry);
+	}
+	
+	/**
+	 * Adds the given subtype to the type.
+	 */
+	protected void addSubType(ITypeInfo type, ITypeInfo subType) {
+		Collection subTypes = (Collection) fTypeToSubTypes.get(type);
+		if (subTypes == null) {
+			subTypes = new ArrayList(INITIAL_SUB_TYPES);
+			fTypeToSubTypes.put(type, subTypes);
+		}
+		if (!subTypes.contains(subType)) {
+			subTypes.add(subType);
+		}
+
+		Collection superEntries = (Collection) fTypeToSuperTypes.get(subType);
+		if (superEntries == null) {
+		    superEntries = new ArrayList(INITIAL_SUPER_TYPES);
+			fTypeToSuperTypes.put(subType, superEntries);
+		}
+		for (Iterator i = superEntries.iterator(); i.hasNext(); ) {
+			TypeEntry entry = (TypeEntry)i.next();
+			if (entry.type.equals(type))
+				return;	// don't add if already exists
+		}
+		// default to private access
+		TypeEntry typeEntry = new TypeEntry(type, ASTAccessVisibility.PRIVATE);
+		superEntries.add(typeEntry);
+	}
+
+	/**
+	 * Returns true if type already has the given supertype.
+	 */
+	public boolean hasSuperType(ITypeInfo type, ITypeInfo superType) {
+		Collection entries = (Collection) fTypeToSuperTypes.get(type);
+		if (entries != null) {
+			for (Iterator i = entries.iterator(); i.hasNext(); ) {
+				TypeEntry entry = (TypeEntry)i.next();
+				if (entry.type.equals(superType))
+					return true;
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * Returns an array of supertypes for the given type - will never return null.
+	 */
+	public ITypeInfo[] getSuperTypes(ITypeInfo type) {
+		Collection entries = (Collection) fTypeToSuperTypes.get(type);
+		if (entries != null) {
+			ArrayList superTypes = new ArrayList(INITIAL_SUPER_TYPES);
+			for (Iterator i = entries.iterator(); i.hasNext(); ) {
+				TypeEntry entry = (TypeEntry)i.next();
+				superTypes.add(entry.type);
+			}
+			return (ITypeInfo[])superTypes.toArray(new ITypeInfo[superTypes.size()]);
+		}
+		return NO_TYPES;
+	}
+	
+	/**
+	 * Returns an array of subtypes for the given type - will never return null.
+	 */
+	public ITypeInfo[] getSubTypes(ITypeInfo type) {
+		Collection subTypes = (Collection) fTypeToSubTypes.get(type);
+		if (subTypes != null) {
+			return (ITypeInfo[])subTypes.toArray(new ITypeInfo[subTypes.size()]);
+		}
+		return NO_TYPES;
+	}
+
+    /* (non-Javadoc)
+     * @see org.eclipse.cdt.core.browser.typehierarchy.ITypeHierarchy#addTypeHierarchyChangedListener(org.eclipse.cdt.core.browser.typehierarchy.ITypeHierarchyChangedListener)
+     */
+    public void addTypeHierarchyChangedListener(ITypeHierarchyChangedListener listener) {
+    	ArrayList listeners = fChangeListeners;
+    	if (listeners == null) {
+    		fChangeListeners = listeners = new ArrayList();
+    	}
+    	
+    	// register with JavaCore to get Java element delta on first listener added
+    	if (listeners.size() == 0) {
+    		CoreModel.getDefault().addElementChangedListener(this);
+    	}
+    	
+    	// add listener only if it is not already present
+    	if (listeners.indexOf(listener) == -1) {
+    		listeners.add(listener);
+    	}
+    }
+
+
+    /**
+     * @see ITypeHierarchy
+     */
+    public synchronized void removeTypeHierarchyChangedListener(ITypeHierarchyChangedListener listener) {
+    	ArrayList listeners = fChangeListeners;
+    	if (listeners == null) {
+    		return;
+    	}
+    	listeners.remove(listener);
+
+    	// deregister from JavaCore on last listener removed
+    	if (listeners.isEmpty()) {
+    		CoreModel.getDefault().removeElementChangedListener(this);
+    	}
+    }
+    
+    /**
+     * Determines if the change effects this hierarchy, and fires
+     * change notification if required.
+     */
+    public void elementChanged(ElementChangedEvent event) {
+    	// type hierarchy change has already been fired
+    	if (fNeedsRefresh) return;
+    	
+    	if (isAffected(event.getDelta())) {
+    		fNeedsRefresh = true;
+    		fireChange();
+    	}
+    }
+    
+    /**
+     * Returns true if the given delta could change this type hierarchy
+     */
+    public synchronized boolean isAffected(ICElementDelta delta) {
+    	ICElement element= delta.getElement();
+//    	switch (element.getElementType()) {
+//    		case ICElement.C_MODEL:
+//    			return isAffectedByCModel(delta, element);
+//    		case ICElement.C_PROJECT:
+//    			return isAffectedByCProject(delta, element);
+//    		case ICElement.C_UNIT:
+//    			return isAffectedByOpenable(delta, element);
+//    	}
+//    	return false;
+    	return true;
+    }
+    
+    /**
+     * Notifies listeners that this hierarchy has changed and needs
+     * refreshing. Note that listeners can be removed as we iterate
+     * through the list.
+     */
+    public void fireChange() {
+    	ArrayList listeners = fChangeListeners;
+    	if (listeners == null) {
+    		return;
+    	}
+    	if (DEBUG) {
+    		System.out.println("FIRING hierarchy change ["+Thread.currentThread()+"]"); //$NON-NLS-1$ //$NON-NLS-2$
+    		if (fFocusType != null) {
+    			System.out.println("    for hierarchy focused on " + fFocusType.toString()); //$NON-NLS-1$
+    		}
+    	}
+    	// clone so that a listener cannot have a side-effect on this list when being notified
+    	listeners = (ArrayList)listeners.clone();
+    	for (int i= 0; i < listeners.size(); i++) {
+    		final ITypeHierarchyChangedListener listener= (ITypeHierarchyChangedListener)listeners.get(i);
+    		Platform.run(new ISafeRunnable() {
+    			public void handleException(Throwable exception) {
+    				Util.log(exception, "Exception occurred in listener of Type hierarchy change notification", ICLogConstants.CDT); //$NON-NLS-1$
+    			}
+    			public void run() throws Exception {
+    				listener.typeHierarchyChanged(TypeHierarchy.this);
+    			}
+    		});
+    	}
+    }
+
+    /* (non-Javadoc)
+     * @see org.eclipse.cdt.core.browser.typehierarchy.ITypeHierarchy#contains(org.eclipse.cdt.core.model.ICElement)
+     */
+    public boolean contains(ICElement type) {
+    	// classes
+	    ITypeInfo info = AllTypesCache.getTypeForElement(type);
+        
+	    if (info == null)
+	        return false;
+        
+    	if (fTypeToSuperTypes.get(info) != null) {
+    		return true;
+    	}
+
+    	// root classes
+    	if (fRootTypes.contains(type)) return true;
+
+        return false;
+    }
+    
+    /**
+     * @see ITypeHierarchy
+     */
+    public boolean exists() {
+    	if (!fNeedsRefresh) return true;
+    	
+    	return (fFocusType == null || fFocusType.exists()) && cProject().exists();
+    }
+    
+    /**
+     * Returns the C project this hierarchy was created in.
+     */
+    public ICProject cProject() {
+        IProject project = fFocusType.getCache().getProject();
+        return findCProject(project);
+    }
+   	private ICProject findCProject(IProject project) {
+		try {
+			ICProject[] cProjects = CoreModel.getDefault().getCModel().getCProjects();
+			if (cProjects != null) {
+				for (int i = 0; i < cProjects.length; ++i) {
+					ICProject cProject = cProjects[i];
+					if (project.equals(cProjects[i].getProject()))
+						return cProject;
+				}
+			}
+		} catch (CModelException e) {
+		}
+		return null;
+	}
+
+    /* (non-Javadoc)
+     * @see org.eclipse.cdt.core.browser.typehierarchy.ITypeHierarchy#getAllClasses()
+     */
+    public ICElement[] getAllClasses() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    /* (non-Javadoc)
+     * @see org.eclipse.cdt.core.browser.typehierarchy.ITypeHierarchy#getRootClasses()
+     */
+    public ICElement[] getRootClasses() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    /* (non-Javadoc)
+     * @see org.eclipse.cdt.core.browser.typehierarchy.ITypeHierarchy#getSubtypes(org.eclipse.cdt.core.model.ICElement)
+     */
+    public ICElement[] getSubtypes(ICElement type) {
+	    List list = new ArrayList();
+	    ITypeInfo info = TypeUtil.getTypeForElement(type);
+		Collection entries = (Collection) fTypeToSubTypes.get(info);
+		if (entries != null) {
+			for (Iterator i = entries.iterator(); i.hasNext(); ) {
+				ITypeInfo subType = (ITypeInfo)i.next();
+				ICElement elem = TypeUtil.getElementForType(subType);
+				if (elem != null) {
+				    list.add(elem);
+				}
+			}
+		}
+		return (ICElement[])list.toArray(new ICElement[list.size()]);
+    }
+
+    /* (non-Javadoc)
+     * @see org.eclipse.cdt.core.browser.typehierarchy.ITypeHierarchy#getAllSuperclasses(org.eclipse.cdt.core.model.ICElement)
+     */
+    public ICElement[] getAllSubtypes(ICElement type) {
+	    List list = new ArrayList();
+	    ITypeInfo info = TypeUtil.getTypeForElement(type);
+	    addSubs(info, list);
+	    //convert list to ICElements
+	    ICElement[] elems = new ICElement[list.size()];
+	    int count = 0;
+	    for (Iterator i = list.iterator(); i.hasNext(); ) {
+	        ITypeInfo subType = (ITypeInfo) i.next();
+	        elems[count++] = TypeUtil.getElementForType(subType);
+	    }
+	    return elems;
+    }
+
+    private void addSubs(ITypeInfo type, List list) {
+		Collection entries = (Collection) fTypeToSubTypes.get(type);
+		if (entries != null) {
+			for (Iterator i = entries.iterator(); i.hasNext(); ) {
+				ITypeInfo subType = (ITypeInfo)i.next();
+				if (!list.contains(subType)) {
+				    list.add(subType);
+				}
+			    addSubs(subType, list);
+			}
+		}
+    }
+
+    /* (non-Javadoc)
+     * @see org.eclipse.cdt.core.browser.typehierarchy.ITypeHierarchy#getSupertypes(org.eclipse.cdt.core.model.ICElement)
+     */
+    public ICElement[] getSupertypes(ICElement type) {
+	    List list = new ArrayList();
+	    ITypeInfo info = TypeUtil.getTypeForElement(type);
+		Collection entries = (Collection) fTypeToSuperTypes.get(info);
+		if (entries != null) {
+			for (Iterator i = entries.iterator(); i.hasNext(); ) {
+				TypeEntry entry = (TypeEntry)i.next();
+				ITypeInfo superType = entry.type;
+				ICElement elem = TypeUtil.getElementForType(superType);
+				if (elem != null) {
+				    list.add(elem);
+				}
+			}
+		}
+		return (ICElement[])list.toArray(new ICElement[list.size()]);
+    }
+
+    /* (non-Javadoc)
+     * @see org.eclipse.cdt.core.browser.typehierarchy.ITypeHierarchy#getAllSuperclasses(org.eclipse.cdt.core.model.ICElement)
+     */
+    public ICElement[] getAllSupertypes(ICElement type) {
+	    List list = new ArrayList();
+	    ITypeInfo info = TypeUtil.getTypeForElement(type);
+	    addSupers(info, list);
+	    //convert list to ICElements
+	    ICElement[] elems = new ICElement[list.size()];
+	    int count = 0;
+	    for (Iterator i = list.iterator(); i.hasNext(); ) {
+	        ITypeInfo superType = (ITypeInfo) i.next();
+	        elems[count++] = TypeUtil.getElementForType(superType);
+	    }
+	    return elems;
+    }
+
+    private void addSupers(ITypeInfo type, List list) {
+		Collection entries = (Collection) fTypeToSuperTypes.get(type);
+		if (entries != null) {
+			for (Iterator i = entries.iterator(); i.hasNext(); ) {
+				TypeEntry entry = (TypeEntry)i.next();
+				ITypeInfo superType = entry.type;
+				if (!list.contains(superType)) {
+				    list.add(superType);
+				}
+			    addSupers(superType, list);
+			}
+		}
+    }
+
+    /* (non-Javadoc)
+     * @see org.eclipse.cdt.core.browser.typehierarchy.ITypeHierarchy#getType()
+     */
+    public ICElement getType() {
+        if (fFocusType != null)
+            return TypeUtil.getElementForType(fFocusType);
+        return null;
+    }
+
+    /**
+     * @see ITypeHierarchy
+     * TODO (jerome) should use a PerThreadObject to build the hierarchy instead of synchronizing
+     * (see also isAffected(IJavaElementDelta))
+     */
+    public synchronized void refresh(IProgressMonitor monitor) throws CModelException {
+    	try {
+    		fProgressMonitor = monitor;
+    		if (monitor != null) {
+    			if (fFocusType != null) {
+    				monitor.beginTask(TypeHierarchyMessages.getFormattedString("hierarchy.creatingOnType", fFocusType.getQualifiedTypeName().getFullyQualifiedName()), 100); //$NON-NLS-1$
+    			} else {
+    				monitor.beginTask(TypeHierarchyMessages.getString("hierarchy.creating"), 100); //$NON-NLS-1$
+    			}
+    		}
+    		long start = -1;
+    		if (DEBUG) {
+    			start = System.currentTimeMillis();
+    			if (fComputeSubtypes) {
+    				System.out.println("CREATING TYPE HIERARCHY [" + Thread.currentThread() + "]"); //$NON-NLS-1$ //$NON-NLS-2$
+    			} else {
+    				System.out.println("CREATING SUPER TYPE HIERARCHY [" + Thread.currentThread() + "]"); //$NON-NLS-1$ //$NON-NLS-2$
+    			}
+    			if (fFocusType != null) {
+    				System.out.println("  on type " + fFocusType.toString()); //$NON-NLS-1$
+    			}
+    		}
+
+    		compute();
+//    		initializeRegions();
+    		fNeedsRefresh = false;
+    		fChangeCollector = null;
+
+    		if (DEBUG) {
+    			if (fComputeSubtypes) {
+    				System.out.println("CREATED TYPE HIERARCHY in " + (System.currentTimeMillis() - start) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$
+    			} else {
+    				System.out.println("CREATED SUPER TYPE HIERARCHY in " + (System.currentTimeMillis() - start) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$
+    			}
+    			System.out.println(this.toString());
+    		}
+    	} catch (CModelException e) {
+    		throw e;
+    	} catch (CoreException e) {
+    		throw new CModelException(e);
+    	} finally {
+    		if (monitor != null) {
+    			monitor.done();
+    		}
+    		fProgressMonitor = null;
+    	}
+    }
+
+    /**
+     * Compute this type hierarchy.
+     */
+    protected void compute() throws CModelException, CoreException {
+    	if (fFocusType != null) {
+//    		HierarchyBuilder builder = 
+//    			new IndexBasedHierarchyBuilder(
+//    				this, 
+//    				this.scope);
+//    		builder.build(this.computeSubtypes);
+    	    
+//			initialize(1);
+//			buildSupertypes();
+    	    
+    	} // else a RegionBasedTypeHierarchy should be used
+    }
+    
+    /**
+     * Initializes this hierarchy's internal tables with the given size.
+     */
+ /*   protected void initialize(int size) {
+    	if (size < 10) {
+    		size = 10;
+    	}
+    	int smallSize = (size / 2);
+    	this.classToSuperclass = new HashMap(size);
+    	this.interfaces = new ArrayList(smallSize);
+    	this.missingTypes = new ArrayList(smallSize);
+    	this.rootClasses = new TypeVector();
+    	this.typeToSubtypes = new HashMap(smallSize);
+    	this.typeToSuperInterfaces = new HashMap(smallSize);
+    	this.typeFlags = new HashMap(smallSize);
+    	
+    	this.projectRegion = new Region();
+    	this.packageRegion = new Region();
+    	this.files = new HashMap(5);
+    }
+*/
+    
+    /* (non-Javadoc)
+     * @see org.eclipse.cdt.core.browser.typehierarchy.ITypeHierarchy#store(java.io.OutputStream, org.eclipse.core.runtime.IProgressMonitor)
+     */
+    public void store(OutputStream outputStream, IProgressMonitor monitor) throws CModelException {
+        // TODO Auto-generated method stub
+        
+    }
+
+}
Index: browser/org/eclipse/cdt/core/browser/typehierarchy/TypeHierarchyBuilder.java
===================================================================
RCS file: browser/org/eclipse/cdt/core/browser/typehierarchy/TypeHierarchyBuilder.java
diff -N browser/org/eclipse/cdt/core/browser/typehierarchy/TypeHierarchyBuilder.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ browser/org/eclipse/cdt/core/browser/typehierarchy/TypeHierarchyBuilder.java	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,129 @@
+/*******************************************************************************
+ * Copyright (c) 2004 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     QNX Software Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.core.browser.typehierarchy;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.eclipse.cdt.core.browser.ITypeInfo;
+import org.eclipse.cdt.core.model.CModelException;
+import org.eclipse.cdt.core.model.ICModelStatusConstants;
+import org.eclipse.cdt.core.parser.ast.ASTAccessVisibility;
+import org.eclipse.cdt.internal.core.browser.cache.TypeCacheManager;
+import org.eclipse.cdt.internal.core.model.CModelStatus;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.jobs.Job;
+
+public class TypeHierarchyBuilder {
+	
+	public TypeHierarchyBuilder() {
+	}
+	
+	public ITypeHierarchy createTypeHierarchy(ITypeInfo info, boolean enableIndexing, IProgressMonitor monitor) throws CModelException {
+		TypeHierarchy typeHierarchy = new TypeHierarchy(info);
+		Set processedTypes = new HashSet();
+		addSuperClasses(typeHierarchy, info, processedTypes, enableIndexing, monitor);
+
+		typeHierarchy.addRootType(info);
+		processedTypes.clear();
+		addSubClasses(typeHierarchy, info, processedTypes, enableIndexing, monitor);
+
+		return typeHierarchy;
+	}
+
+	private void addSuperClasses(TypeHierarchy typeHierarchy, ITypeInfo type, Set processedTypes, boolean enableIndexing, IProgressMonitor monitor) throws CModelException {
+		if (type.hasSuperTypes()) {
+			ITypeInfo[] superTypes = TypeCacheManager.getInstance().locateSuperTypesAndWait(type, enableIndexing, Job.SHORT, monitor);
+			if (superTypes == null)
+				throw new CModelException(new CModelStatus(ICModelStatusConstants.ELEMENT_DOES_NOT_EXIST));
+			
+			for (int i = 0; i < superTypes.length; ++i) {
+				ITypeInfo superType = superTypes[i];
+				
+				// recursively process sub sub classes
+				if (!processedTypes.contains(superType)) {
+					processedTypes.add(superType);
+					addSuperClasses(typeHierarchy, superType, processedTypes, enableIndexing, monitor);
+				}
+				
+				ASTAccessVisibility access = type.getSuperTypeAccess(superType);
+				
+				typeHierarchy.addSuperType(type, superType, access);
+			}
+		} else {
+			typeHierarchy.addRootType(type);
+		}
+	}
+
+	private void addSubClasses(TypeHierarchy typeHierarchy, ITypeInfo type, Set processedTypes, boolean enableIndexing, IProgressMonitor monitor) throws CModelException {
+		if (type.hasSubTypes()) {
+			ITypeInfo[] subTypes = TypeCacheManager.getInstance().locateSubTypesAndWait(type, enableIndexing, Job.SHORT, monitor);
+			if (subTypes == null)
+				throw new CModelException(new CModelStatus(ICModelStatusConstants.ELEMENT_DOES_NOT_EXIST));
+			
+			for (int i = 0; i < subTypes.length; ++i) {
+				ITypeInfo subType = subTypes[i];
+				
+				// recursively process sub sub classes
+				if (!processedTypes.contains(subType)) {
+					processedTypes.add(subType);
+					addSubClasses(typeHierarchy, subType, processedTypes, enableIndexing, monitor);
+				}
+				
+				typeHierarchy.addSubType(type, subType);
+			}
+		}
+	}
+
+/*
+ 	private IStructure findCElementForType(ITypeInfo info, boolean enableIndexing, IProgressMonitor monitor) throws CModelException {
+		if (!info.exists())
+			throw new CModelException(new CModelStatus(ICModelStatusConstants.ELEMENT_DOES_NOT_EXIST));
+
+		if (!info.isClass())
+			throw new CModelException(new CModelStatus(ICModelStatusConstants.INVALID_ELEMENT_TYPES));
+	
+		// first we need to resolve the type location
+		ITypeReference location = TypeCacheManager.getInstance().locateTypeAndWait(info, enableIndexing, Job.SHORT, monitor);
+		if (location == null)
+			throw new CModelException(new CModelStatus(ICModelStatusConstants.ELEMENT_DOES_NOT_EXIST));
+		
+		ICElement cElem = location.getCElement();
+		if (cElem == null)
+			throw new CModelException(new CModelStatus(ICModelStatusConstants.ELEMENT_DOES_NOT_EXIST));
+		
+		if (!(cElem instanceof IStructure))
+			throw new CModelException(new CModelStatus(ICModelStatusConstants.INVALID_ELEMENT_TYPES));
+		
+		IStructure cClass = (IStructure)cElem;
+	
+		// check if type exists in cache
+		ITypeInfo type = TypeCacheManager.getInstance().getTypeForElement(cElem);
+		if (type == null || !type.equals(info))
+			throw new CModelException(new CModelStatus(ICModelStatusConstants.ELEMENT_DOES_NOT_EXIST));
+		
+		return cClass;
+	}
+	
+	private ITypeInfo findTypeInCache(ITypeCache cache, String name) {
+		IQualifiedTypeName qualName = new QualifiedTypeName(name);
+		ITypeInfo[] superTypes = cache.getTypes(qualName);
+		for (int i = 0; i < superTypes.length; ++i) {
+			ITypeInfo superType = superTypes[i];
+			if (superType.isClass()) {
+				return superType;
+			}
+		}
+		return null;
+	}
+*/
+	
+}
Index: browser/org/eclipse/cdt/core/browser/typehierarchy/TypeHierarchyMessages.java
===================================================================
RCS file: browser/org/eclipse/cdt/core/browser/typehierarchy/TypeHierarchyMessages.java
diff -N browser/org/eclipse/cdt/core/browser/typehierarchy/TypeHierarchyMessages.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ browser/org/eclipse/cdt/core/browser/typehierarchy/TypeHierarchyMessages.java	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2004 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     QNX Software Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.core.browser.typehierarchy;
+
+import java.text.MessageFormat;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+public class TypeHierarchyMessages {
+
+	private static final String RESOURCE_BUNDLE= TypeHierarchyMessages.class.getName();
+
+	private static ResourceBundle fgResourceBundle;
+	static {
+		try {
+			fgResourceBundle = ResourceBundle.getBundle(RESOURCE_BUNDLE);
+		} catch (MissingResourceException x) {
+			fgResourceBundle = null;
+		}
+	}
+
+	private TypeHierarchyMessages() {
+	}
+
+	public static String getString(String key) {
+		try {
+			return fgResourceBundle.getString(key);
+		} catch (MissingResourceException e) {
+			return '!' + key + '!';
+		} catch (NullPointerException e) {
+			return "#" + key + "#"; //$NON-NLS-1$ //$NON-NLS-2$
+		}
+	}
+	
+	public static String getFormattedString(String key, String arg) {
+		return getFormattedString(key, new String[] { arg });
+	}
+	
+	public static String getFormattedString(String key, String[] args) {
+		return MessageFormat.format(getString(key), args);	
+	}	
+}
Index: browser/org/eclipse/cdt/core/browser/typehierarchy/TypeHierarchyMessages.properties
===================================================================
RCS file: browser/org/eclipse/cdt/core/browser/typehierarchy/TypeHierarchyMessages.properties
diff -N browser/org/eclipse/cdt/core/browser/typehierarchy/TypeHierarchyMessages.properties
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ browser/org/eclipse/cdt/core/browser/typehierarchy/TypeHierarchyMessages.properties	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,17 @@
+###############################################################################
+# Copyright (c) 2000, 2004 QNX Software Systems and others.
+# All rights reserved. This program and the accompanying materials 
+# are made available under the terms of the Common Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/cpl-v10.html
+# 
+# Contributors:
+#     QNX Software Systems - Initial API and implementation
+###############################################################################
+
+### hierarchy
+hierarchy.nullProject = Project argument cannot be null
+hierarchy.nullRegion = Region cannot be null
+hierarchy.nullFocusType = Type focus cannot be null
+hierarchy.creating = Creating type hierarchy...
+hierarchy.creatingOnType = Creating type hierarchy on {0}...
Index: browser/org/eclipse/cdt/internal/core/browser/cache/SubTypeLocatorJob.java
===================================================================
RCS file: browser/org/eclipse/cdt/internal/core/browser/cache/SubTypeLocatorJob.java
diff -N browser/org/eclipse/cdt/internal/core/browser/cache/SubTypeLocatorJob.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ browser/org/eclipse/cdt/internal/core/browser/cache/SubTypeLocatorJob.java	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (c) 2004 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     QNX Software Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.internal.core.browser.cache;
+
+import org.eclipse.cdt.core.browser.ITypeInfo;
+import org.eclipse.cdt.core.browser.IWorkingCopyProvider;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.SubProgressMonitor;
+
+public class SubTypeLocatorJob extends BasicJob {
+
+	public static final Object FAMILY = new Object();
+	private ITypeInfo fLocateType;
+	private ITypeCache fTypeCache;
+	private IWorkingCopyProvider fWorkingCopyProvider;
+	
+	public SubTypeLocatorJob(ITypeInfo info, ITypeCache typeCache, IWorkingCopyProvider workingCopyProvider) {
+		super(TypeCacheMessages.getString("SubTypeLocatorJob.jobName"), FAMILY); //$NON-NLS-1$
+		fLocateType = info;
+		fTypeCache = typeCache;
+		fWorkingCopyProvider= workingCopyProvider;
+	}
+	
+	public ITypeInfo getType() {
+		return fLocateType;
+	}
+
+	protected IStatus runWithDelegatedProgress(IProgressMonitor monitor) throws InterruptedException {
+		boolean success = false;
+		long startTime = System.currentTimeMillis();
+		trace("SubTypeLocatorJob: started"); //$NON-NLS-1$
+
+		try {
+			monitor.beginTask(TypeCacheMessages.getString("SubTypeLocatorJob.taskName"), 100); //$NON-NLS-1$
+			
+			if (monitor.isCanceled())
+				throw new InterruptedException();
+			
+			TypeParser parser = new TypeParser(fTypeCache, fWorkingCopyProvider);
+			success = parser.findSubTypes(fLocateType, new SubProgressMonitor(monitor, 100));
+
+			if (monitor.isCanceled())
+				throw new InterruptedException();
+			
+		} finally {
+			long executionTime = System.currentTimeMillis() - startTime;
+			if (success)
+				trace("SubTypeLocatorJob: completed ("+ executionTime + " ms)"); //$NON-NLS-1$ //$NON-NLS-2$
+			else
+				trace("SubTypeLocatorJob: aborted ("+ executionTime + " ms)"); //$NON-NLS-1$ //$NON-NLS-2$
+
+			monitor.done();
+		}
+
+		return Status.OK_STATUS;
+	}
+}
