/******************************************************************************* * Copyright (c) 2000, 2009 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.jdt.internal.core.hierarchy; import java.util.ArrayList; import org.eclipse.core.runtime.CoreException; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaElementDelta; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IOpenable; import org.eclipse.jdt.core.IPackageFragmentRoot; import org.eclipse.jdt.core.IRegion; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.search.IJavaSearchScope; import org.eclipse.jdt.internal.core.CompilationUnit; import org.eclipse.jdt.internal.core.JavaElement; import org.eclipse.jdt.internal.core.Openable; import org.eclipse.jdt.internal.core.Region; import org.eclipse.jdt.internal.core.TypeVector; public class RegionBasedTypeHierarchy extends TypeHierarchy { /** * The region of types for which to build the hierarchy */ protected IRegion region; /** * Creates a TypeHierarchy on the types in the specified region, considering first the given * working copies, using the projects in the given region for a name lookup context. If a * specific type is also specified, the type hierarchy is pruned to only contain the branch * including the specified type. */ public RegionBasedTypeHierarchy(IRegion region, ICompilationUnit[] workingCopies, IType type, boolean computeSubtypes) { super(type, workingCopies, (IJavaSearchScope)null, computeSubtypes); Region newRegion= new Region() { public void add(IJavaElement element) { if (!contains(element)) { //"new" element added to region removeAllChildren(element); this.rootElements.add(element); if (element.getElementType() == IJavaElement.JAVA_PROJECT) { // add jar roots as well so that jars don't rely on their parent to know // if they are contained in the region // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=146615) try { IPackageFragmentRoot[] roots= ((IJavaProject)element).getPackageFragmentRoots(); for (int i= 0, length= roots.length; i < length; i++) { if (roots[i].isArchive() && !this.rootElements.contains(roots[i])) this.rootElements.add(roots[i]); } } catch (JavaModelException e) { // project doesn't exist } } this.rootElements.trimToSize(); } } }; IJavaElement[] elements= region.getElements(); for (int i= 0, length= elements.length; i < length; i++) { newRegion.add(elements[i]); } this.region= newRegion; if (elements.length > 0) this.project= elements[0].getJavaProject(); } /* * @see TypeHierarchy#initializeRegions */ protected void initializeRegions() { super.initializeRegions(); IJavaElement[] roots= this.region.getElements(); for (int i= 0; i < roots.length; i++) { IJavaElement root= roots[i]; if (root instanceof IOpenable) { this.files.put(root, new ArrayList()); } else { Openable o= (Openable)((JavaElement)root).getOpenableParent(); if (o != null) { this.files.put(o, new ArrayList()); } } checkCanceled(); } } /** * Compute this type hierarchy. */ protected void compute() throws JavaModelException, CoreException { HierarchyBuilder builder= new RegionBasedHierarchyBuilder(this); builder.build(this.computeSubtypes); } protected boolean isAffectedByOpenable(IJavaElementDelta delta, IJavaElement element, int eventType) { // change to working copy if (element instanceof CompilationUnit && ((CompilationUnit)element).isWorkingCopy()) { return super.isAffectedByOpenable(delta, element, eventType); } // if no focus, hierarchy is affected if the element is part of the region if (this.focusType == null) { return this.region.contains(element); } else { return super.isAffectedByOpenable(delta, element, eventType); } } /** * Returns the java project this hierarchy was created in. */ public IJavaProject javaProject() { return this.project; } public void pruneDeadBranches() { pruneDeadBranches(getRootClasses()); pruneDeadBranches(getRootInterfaces()); } /* * Returns whether all subtypes of the given type have been pruned. */ private boolean pruneDeadBranches(IType type) { TypeVector subtypes= (TypeVector)this.typeToSubtypes.get(type); if (subtypes == null) return true; pruneDeadBranches(subtypes.copy().elements()); subtypes= (TypeVector)this.typeToSubtypes.get(type); return (subtypes == null || subtypes.size == 0); } private void pruneDeadBranches(IType[] types) { for (int i= 0, length= types.length; i < length; i++) { IType type= types[i]; if (pruneDeadBranches(type) && !this.region.contains(type)) { removeType(type); } } } /** * Removes all the subtypes of the given type from the type hierarchy, removes its superclass * entry and removes the references from its super types. */ protected void removeType(IType type) { IType[] subtypes= getSubtypes(type); this.typeToSubtypes.remove(type); if (subtypes != null) { for (int i= 0; i < subtypes.length; i++) { removeType(subtypes[i]); } } IType superclass= (IType)this.classToSuperclass.remove(type); if (superclass != null) { TypeVector types= (TypeVector)this.typeToSubtypes.get(superclass); if (types != null) types.remove(type); } IType[] superinterfaces= (IType[])this.typeToSuperInterfaces.remove(type); if (superinterfaces != null) { for (int i= 0, length= superinterfaces.length; i < length; i++) { IType superinterface= superinterfaces[i]; TypeVector types= (TypeVector)this.typeToSubtypes.get(superinterface); if (types != null) types.remove(type); } } this.interfaces.remove(type); } }