001: /*******************************************************************************
002: * Copyright (c) 2000, 2006 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.HashMap;
013: import java.util.Map;
014:
015: import org.eclipse.core.resources.IFile;
016: import org.eclipse.core.resources.IResource;
017: import org.eclipse.core.runtime.CoreException;
018: import org.eclipse.core.runtime.IProgressMonitor;
019: import org.eclipse.core.runtime.OperationCanceledException;
020: import org.eclipse.jdt.core.IType;
021: import org.eclipse.jdt.core.JavaModelException;
022: import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
023: import org.eclipse.jdt.internal.compiler.env.IBinaryType;
024: import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
025: import org.eclipse.jdt.internal.compiler.env.IGenericType;
026: import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
027: import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
028: import org.eclipse.jdt.internal.core.*;
029: import org.eclipse.jdt.internal.core.util.ResourceCompilationUnit;
030: import org.eclipse.jdt.internal.core.util.Util;
031:
032: public abstract class HierarchyBuilder {
033: /**
034: * The hierarchy being built.
035: */
036: protected TypeHierarchy hierarchy;
037: /**
038: * @see NameLookup
039: */
040: protected NameLookup nameLookup;
041: /**
042: * The resolver used to resolve type hierarchies
043: * @see HierarchyResolver
044: */
045: protected HierarchyResolver hierarchyResolver;
046: /**
047: * A temporary cache of infos to handles to speed info
048: * to handle translation - it only contains the entries
049: * for the types in the region (in other words, it contains
050: * no supertypes outside the region).
051: */
052: protected Map infoToHandle;
053: /*
054: * The dot-separated fully qualified name of the focus type, or null of none.
055: */
056: protected String focusQualifiedName;
057:
058: public HierarchyBuilder(TypeHierarchy hierarchy)
059: throws JavaModelException {
060:
061: this .hierarchy = hierarchy;
062: JavaProject project = (JavaProject) hierarchy.javaProject();
063:
064: IType focusType = hierarchy.getType();
065: org.eclipse.jdt.core.ICompilationUnit unitToLookInside = focusType == null ? null
066: : focusType.getCompilationUnit();
067: org.eclipse.jdt.core.ICompilationUnit[] workingCopies = this .hierarchy.workingCopies;
068: org.eclipse.jdt.core.ICompilationUnit[] unitsToLookInside;
069: if (unitToLookInside != null) {
070: int wcLength = workingCopies == null ? 0
071: : workingCopies.length;
072: if (wcLength == 0) {
073: unitsToLookInside = new org.eclipse.jdt.core.ICompilationUnit[] { unitToLookInside };
074: } else {
075: unitsToLookInside = new org.eclipse.jdt.core.ICompilationUnit[wcLength + 1];
076: unitsToLookInside[0] = unitToLookInside;
077: System.arraycopy(workingCopies, 0, unitsToLookInside,
078: 1, wcLength);
079: }
080: } else {
081: unitsToLookInside = workingCopies;
082: }
083: if (project != null) {
084: SearchableEnvironment searchableEnvironment = project
085: .newSearchableNameEnvironment(unitsToLookInside);
086: this .nameLookup = searchableEnvironment.nameLookup;
087: this .hierarchyResolver = new HierarchyResolver(
088: searchableEnvironment, project.getOptions(true),
089: this , new DefaultProblemFactory());
090: }
091: this .infoToHandle = new HashMap(5);
092: this .focusQualifiedName = focusType == null ? null : focusType
093: .getFullyQualifiedName();
094: }
095:
096: public abstract void build(boolean computeSubtypes)
097: throws JavaModelException, CoreException;
098:
099: /**
100: * Configure this type hierarchy by computing the supertypes only.
101: */
102: protected void buildSupertypes() {
103: IType focusType = this .getType();
104: if (focusType == null)
105: return;
106: // get generic type from focus type
107: IGenericType type;
108: try {
109: type = (IGenericType) ((JavaElement) focusType)
110: .getElementInfo();
111: } catch (JavaModelException e) {
112: // if the focus type is not present, or if cannot get workbench path
113: // we cannot create the hierarchy
114: return;
115: }
116: //NB: no need to set focus type on hierarchy resolver since no other type is injected
117: // in the hierarchy resolver, thus there is no need to check that a type is
118: // a sub or super type of the focus type.
119: this .hierarchyResolver.resolve(type);
120:
121: // Add focus if not already in (case of a type with no explicit super type)
122: if (!this .hierarchy.contains(focusType)) {
123: this .hierarchy.addRootClass(focusType);
124: }
125: }
126:
127: /**
128: * Connect the supplied type to its superclass & superinterfaces.
129: * The superclass & superinterfaces are the identical binary or source types as
130: * supplied by the name environment.
131: */
132: public void connect(IGenericType type, IType typeHandle,
133: IType super classHandle, IType[] super interfaceHandles) {
134:
135: /*
136: * Temporary workaround for 1G2O5WK: ITPJCORE:WINNT - NullPointerException when selecting "Show in Type Hierarchy" for a inner class
137: */
138: if (typeHandle == null)
139: return;
140: if (TypeHierarchy.DEBUG) {
141: System.out
142: .println("Connecting: " + ((JavaElement) typeHandle).toStringWithAncestors()); //$NON-NLS-1$
143: System.out.println(" to superclass: " //$NON-NLS-1$
144: + (super classHandle == null ? "<None>" //$NON-NLS-1$
145: : ((JavaElement) super classHandle)
146: .toStringWithAncestors()));
147: System.out.print(" and superinterfaces:"); //$NON-NLS-1$
148: if (super interfaceHandles == null
149: || super interfaceHandles.length == 0) {
150: System.out.println(" <None>"); //$NON-NLS-1$
151: } else {
152: System.out.println();
153: for (int i = 0, length = super interfaceHandles.length; i < length; i++) {
154: if (super interfaceHandles[i] == null)
155: continue;
156: System.out
157: .println(" " + ((JavaElement) super interfaceHandles[i]).toStringWithAncestors()); //$NON-NLS-1$
158: }
159: }
160: }
161: // now do the caching
162: switch (TypeDeclaration.kind(type.getModifiers())) {
163: case TypeDeclaration.CLASS_DECL:
164: case TypeDeclaration.ENUM_DECL:
165: if (super classHandle == null) {
166: this .hierarchy.addRootClass(typeHandle);
167: } else {
168: this .hierarchy.cacheSuperclass(typeHandle,
169: super classHandle);
170: }
171: break;
172: case TypeDeclaration.INTERFACE_DECL:
173: case TypeDeclaration.ANNOTATION_TYPE_DECL:
174: this .hierarchy.addInterface(typeHandle);
175: break;
176: }
177: if (super interfaceHandles == null) {
178: super interfaceHandles = TypeHierarchy.NO_TYPE;
179: }
180: this .hierarchy.cacheSuperInterfaces(typeHandle,
181: super interfaceHandles);
182:
183: // record flags
184: this .hierarchy.cacheFlags(typeHandle, type.getModifiers());
185: }
186:
187: /**
188: * Returns a handle for the given generic type or null if not found.
189: */
190: protected IType getHandle(IGenericType genericType,
191: ReferenceBinding binding) {
192: if (genericType == null)
193: return null;
194: if (genericType instanceof HierarchyType) {
195: IType handle = (IType) this .infoToHandle.get(genericType);
196: if (handle == null) {
197: handle = ((HierarchyType) genericType).typeHandle;
198: handle = (IType) ((JavaElement) handle)
199: .resolved(binding);
200: this .infoToHandle.put(genericType, handle);
201: }
202: return handle;
203: } else if (genericType.isBinaryType()) {
204: ClassFile classFile = (ClassFile) this .infoToHandle
205: .get(genericType);
206: // if it's null, it's from outside the region, so do lookup
207: if (classFile == null) {
208: IType handle = lookupBinaryHandle((IBinaryType) genericType);
209: if (handle == null)
210: return null;
211: // case of an anonymous type (see 1G2O5WK: ITPJCORE:WINNT - NullPointerException when selecting "Show in Type Hierarchy" for a inner class)
212: // optimization: remember the handle for next call (case of java.io.Serializable that a lot of classes implement)
213: classFile = (ClassFile) handle.getParent();
214: this .infoToHandle.put(genericType, classFile);
215: }
216: return new ResolvedBinaryType(classFile, classFile
217: .getTypeName(), new String(binding
218: .computeUniqueKey()));
219: } else if (genericType instanceof SourceTypeElementInfo) {
220: IType handle = ((SourceTypeElementInfo) genericType)
221: .getHandle();
222: return (IType) ((JavaElement) handle).resolved(binding);
223: } else
224: return null;
225: }
226:
227: protected IType getType() {
228: return this .hierarchy.getType();
229: }
230:
231: /**
232: * Looks up and returns a handle for the given binary info.
233: */
234: protected IType lookupBinaryHandle(IBinaryType typeInfo) {
235: int flag;
236: String qualifiedName;
237: switch (TypeDeclaration.kind(typeInfo.getModifiers())) {
238: case TypeDeclaration.CLASS_DECL:
239: flag = NameLookup.ACCEPT_CLASSES;
240: break;
241: case TypeDeclaration.INTERFACE_DECL:
242: flag = NameLookup.ACCEPT_INTERFACES;
243: break;
244: case TypeDeclaration.ENUM_DECL:
245: flag = NameLookup.ACCEPT_ENUMS;
246: break;
247: default:
248: //case IGenericType.ANNOTATION :
249: flag = NameLookup.ACCEPT_ANNOTATIONS;
250: break;
251: }
252: char[] bName = typeInfo.getName();
253: qualifiedName = new String(ClassFile.translatedName(bName));
254: if (qualifiedName.equals(this .focusQualifiedName))
255: return getType();
256: NameLookup.Answer answer = this .nameLookup.findType(
257: qualifiedName, false, flag,
258: true/* consider secondary types */,
259: false/* do NOT wait for indexes */,
260: false/*don't check restrictions*/, null);
261: return answer == null || answer.type == null
262: || !answer.type.isBinary() ? null : answer.type;
263:
264: }
265:
266: protected void worked(IProgressMonitor monitor, int work) {
267: if (monitor != null) {
268: if (monitor.isCanceled()) {
269: throw new OperationCanceledException();
270: } else {
271: monitor.worked(work);
272: }
273: }
274: }
275:
276: /**
277: * Create an ICompilationUnit info from the given compilation unit on disk.
278: */
279: protected ICompilationUnit createCompilationUnitFromPath(
280: Openable handle, IFile file) {
281: final char[] elementName = handle.getElementName()
282: .toCharArray();
283: return new ResourceCompilationUnit(file, file.getLocationURI()) {
284: public char[] getFileName() {
285: return elementName;
286: }
287: };
288: }
289:
290: /**
291: * Creates the type info from the given class file on disk and
292: * adds it to the given list of infos.
293: */
294: protected IBinaryType createInfoFromClassFile(Openable handle,
295: IResource file) {
296: IBinaryType info = null;
297: try {
298: info = Util.newClassFileReader(file);
299: } catch (org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException e) {
300: if (TypeHierarchy.DEBUG) {
301: e.printStackTrace();
302: }
303: return null;
304: } catch (java.io.IOException e) {
305: if (TypeHierarchy.DEBUG) {
306: e.printStackTrace();
307: }
308: return null;
309: } catch (CoreException e) {
310: if (TypeHierarchy.DEBUG) {
311: e.printStackTrace();
312: }
313: return null;
314: }
315: this .infoToHandle.put(info, handle);
316: return info;
317: }
318:
319: /**
320: * Create a type info from the given class file in a jar and adds it to the given list of infos.
321: */
322: protected IBinaryType createInfoFromClassFileInJar(
323: Openable classFile) {
324: PackageFragment pkg = (PackageFragment) classFile.getParent();
325: String classFilePath = Util.concatWith(pkg.names, classFile
326: .getElementName(), '/');
327: IBinaryType info = null;
328: java.util.zip.ZipFile zipFile = null;
329: try {
330: zipFile = ((JarPackageFragmentRoot) pkg.getParent())
331: .getJar();
332: info = org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader
333: .read(zipFile, classFilePath);
334: } catch (org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException e) {
335: if (TypeHierarchy.DEBUG) {
336: e.printStackTrace();
337: }
338: return null;
339: } catch (java.io.IOException e) {
340: if (TypeHierarchy.DEBUG) {
341: e.printStackTrace();
342: }
343: return null;
344: } catch (CoreException e) {
345: if (TypeHierarchy.DEBUG) {
346: e.printStackTrace();
347: }
348: return null;
349: } finally {
350: JavaModelManager.getJavaModelManager()
351: .closeZipFile(zipFile);
352: }
353: this.infoToHandle.put(info, classFile);
354: return info;
355: }
356:
357: }
|