001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.internal.core.hierarchy;
011:
012: import java.util.ArrayList;
013:
014: import org.eclipse.core.runtime.CoreException;
015: import org.eclipse.jdt.core.*;
016: import org.eclipse.jdt.core.search.IJavaSearchScope;
017: import org.eclipse.jdt.internal.core.CompilationUnit;
018: import org.eclipse.jdt.internal.core.JavaElement;
019: import org.eclipse.jdt.internal.core.Openable;
020: import org.eclipse.jdt.internal.core.Region;
021: import org.eclipse.jdt.internal.core.TypeVector;
022:
023: public class RegionBasedTypeHierarchy extends TypeHierarchy {
024: /**
025: * The region of types for which to build the hierarchy
026: */
027: protected IRegion region;
028:
029: /**
030: * Creates a TypeHierarchy on the types in the specified region,
031: * considering first the given working copies,
032: * using the projects in the given region for a name lookup context. If a specific
033: * type is also specified, the type hierarchy is pruned to only
034: * contain the branch including the specified type.
035: */
036: public RegionBasedTypeHierarchy(IRegion region,
037: ICompilationUnit[] workingCopies, IType type,
038: boolean computeSubtypes) {
039: super (type, workingCopies, (IJavaSearchScope) null,
040: computeSubtypes);
041:
042: Region newRegion = new Region() {
043: public void add(IJavaElement element) {
044: if (!contains(element)) {
045: //"new" element added to region
046: removeAllChildren(element);
047: fRootElements.add(element);
048: if (element.getElementType() == IJavaElement.JAVA_PROJECT) {
049: // add jar roots as well so that jars don't rely on their parent to know
050: // if they are contained in the region
051: // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=146615)
052: try {
053: IPackageFragmentRoot[] roots = ((IJavaProject) element)
054: .getPackageFragmentRoots();
055: for (int i = 0, length = roots.length; i < length; i++) {
056: if (roots[i].isArchive()
057: && !fRootElements
058: .contains(roots[i]))
059: fRootElements.add(roots[i]);
060: }
061: } catch (JavaModelException e) {
062: // project doesn't exist
063: }
064: }
065: fRootElements.trimToSize();
066: }
067: }
068: };
069: IJavaElement[] elements = region.getElements();
070: for (int i = 0, length = elements.length; i < length; i++) {
071: newRegion.add(elements[i]);
072:
073: }
074: this .region = newRegion;
075: if (elements.length > 0)
076: this .project = elements[0].getJavaProject();
077: }
078:
079: /*
080: * @see TypeHierarchy#initializeRegions
081: */
082: protected void initializeRegions() {
083: super .initializeRegions();
084: IJavaElement[] roots = this .region.getElements();
085: for (int i = 0; i < roots.length; i++) {
086: IJavaElement root = roots[i];
087: if (root instanceof IOpenable) {
088: this .files.put(root, new ArrayList());
089: } else {
090: Openable o = (Openable) ((JavaElement) root)
091: .getOpenableParent();
092: if (o != null) {
093: this .files.put(o, new ArrayList());
094: }
095: }
096: checkCanceled();
097: }
098: }
099:
100: /**
101: * Compute this type hierarchy.
102: */
103: protected void compute() throws JavaModelException, CoreException {
104: HierarchyBuilder builder = new RegionBasedHierarchyBuilder(this );
105: builder.build(this .computeSubtypes);
106: }
107:
108: protected boolean isAffectedByOpenable(IJavaElementDelta delta,
109: IJavaElement element) {
110: // change to working copy
111: if (element instanceof CompilationUnit
112: && ((CompilationUnit) element).isWorkingCopy()) {
113: return super .isAffectedByOpenable(delta, element);
114: }
115:
116: // if no focus, hierarchy is affected if the element is part of the region
117: if (this .focusType == null) {
118: return this .region.contains(element);
119: } else {
120: return super .isAffectedByOpenable(delta, element);
121: }
122: }
123:
124: /**
125: * Returns the java project this hierarchy was created in.
126: */
127: public IJavaProject javaProject() {
128: return this .project;
129: }
130:
131: public void pruneDeadBranches() {
132: pruneDeadBranches(getRootClasses());
133: pruneDeadBranches(getRootInterfaces());
134: }
135:
136: /*
137: * Returns whether all subtypes of the given type have been pruned.
138: */
139: private boolean pruneDeadBranches(IType type) {
140: TypeVector subtypes = (TypeVector) this .typeToSubtypes
141: .get(type);
142: if (subtypes == null)
143: return true;
144: pruneDeadBranches(subtypes.copy().elements());
145: subtypes = (TypeVector) this .typeToSubtypes.get(type);
146: return (subtypes == null || subtypes.size == 0);
147: }
148:
149: private void pruneDeadBranches(IType[] types) {
150: for (int i = 0, length = types.length; i < length; i++) {
151: IType type = types[i];
152: if (pruneDeadBranches(type) && !this .region.contains(type)) {
153: removeType(type);
154: }
155: }
156: }
157:
158: /**
159: * Removes all the subtypes of the given type from the type hierarchy,
160: * removes its superclass entry and removes the references from its super types.
161: */
162: protected void removeType(IType type) {
163: IType[] subtypes = this .getSubtypes(type);
164: this .typeToSubtypes.remove(type);
165: if (subtypes != null) {
166: for (int i = 0; i < subtypes.length; i++) {
167: this .removeType(subtypes[i]);
168: }
169: }
170: IType super class = (IType) this .classToSuperclass.remove(type);
171: if (super class != null) {
172: TypeVector types = (TypeVector) this .typeToSubtypes
173: .get(super class);
174: if (types != null)
175: types.remove(type);
176: }
177: IType[] super interfaces = (IType[]) this .typeToSuperInterfaces
178: .remove(type);
179: if (super interfaces != null) {
180: for (int i = 0, length = super interfaces.length; i < length; i++) {
181: IType super interface = super interfaces[i];
182: TypeVector types = (TypeVector) this.typeToSubtypes
183: .get(superinterface);
184: if (types != null)
185: types.remove(type);
186: }
187: }
188: this.interfaces.remove(type);
189: }
190:
191: }
|