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: /**
013: * This is the public entry point to resolve type hierarchies.
014: *
015: * When requesting additional types from the name environment, the resolver
016: * accepts all forms (binary, source & compilation unit) for additional types.
017: *
018: * Side notes: Binary types already know their resolved supertypes so this
019: * only makes sense for source types. Even though the compiler finds all binary
020: * types to complete the hierarchy of a given source type, is there any reason
021: * why the requestor should be informed that binary type X subclasses Y &
022: * implements I & J?
023: */
024:
025: import java.util.HashMap;
026: import java.util.HashSet;
027: import java.util.Map;
028:
029: import org.eclipse.core.resources.IFile;
030: import org.eclipse.core.resources.IResource;
031: import org.eclipse.core.runtime.IPath;
032: import org.eclipse.core.runtime.IProgressMonitor;
033: import org.eclipse.core.runtime.OperationCanceledException;
034: import org.eclipse.jdt.core.IType;
035: import org.eclipse.jdt.core.JavaModelException;
036: import org.eclipse.jdt.core.Signature;
037: import org.eclipse.jdt.core.compiler.CharOperation;
038: import org.eclipse.jdt.internal.compiler.CompilationResult;
039: import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies;
040: import org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy;
041: import org.eclipse.jdt.internal.compiler.IProblemFactory;
042: import org.eclipse.jdt.internal.compiler.ast.*;
043: import org.eclipse.jdt.internal.compiler.env.AccessRestriction;
044: import org.eclipse.jdt.internal.compiler.env.IBinaryType;
045: import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
046: import org.eclipse.jdt.internal.compiler.env.IGenericType;
047: import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
048: import org.eclipse.jdt.internal.compiler.env.ISourceType;
049: import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
050: import org.eclipse.jdt.internal.compiler.impl.ITypeRequestor;
051: import org.eclipse.jdt.internal.compiler.lookup.*;
052: import org.eclipse.jdt.internal.compiler.parser.Parser;
053: import org.eclipse.jdt.internal.compiler.parser.SourceTypeConverter;
054: import org.eclipse.jdt.internal.compiler.problem.AbortCompilation;
055: import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
056: import org.eclipse.jdt.internal.compiler.util.Messages;
057: import org.eclipse.jdt.internal.core.*;
058: import org.eclipse.jdt.internal.core.util.ASTNodeFinder;
059: import org.eclipse.jdt.internal.core.util.HandleFactory;
060:
061: public class HierarchyResolver implements ITypeRequestor {
062:
063: private ReferenceBinding focusType;
064: private boolean super TypesOnly;
065: private boolean hasMissingSuperClass;
066: LookupEnvironment lookupEnvironment;
067: private CompilerOptions options;
068: HierarchyBuilder builder;
069: private ReferenceBinding[] typeBindings;
070:
071: private int typeIndex;
072: private IGenericType[] typeModels;
073:
074: public HierarchyResolver(INameEnvironment nameEnvironment,
075: Map settings, HierarchyBuilder builder,
076: IProblemFactory problemFactory) {
077: // create a problem handler with the 'exit after all problems' handling policy
078: this .options = new CompilerOptions(settings);
079: IErrorHandlingPolicy policy = DefaultErrorHandlingPolicies
080: .exitAfterAllProblems();
081: ProblemReporter problemReporter = new ProblemReporter(policy,
082: this .options, problemFactory);
083:
084: this .setEnvironment(new LookupEnvironment(this , this .options,
085: problemReporter, nameEnvironment), builder);
086: }
087:
088: public HierarchyResolver(LookupEnvironment lookupEnvironment,
089: HierarchyBuilder builder) {
090: this .setEnvironment(lookupEnvironment, builder);
091: }
092:
093: /**
094: * Add an additional binary type
095: * @param binaryType
096: * @param packageBinding
097: */
098: public void accept(IBinaryType binaryType,
099: PackageBinding packageBinding,
100: AccessRestriction accessRestriction) {
101: IProgressMonitor progressMonitor = this .builder.hierarchy.progressMonitor;
102: if (progressMonitor != null && progressMonitor.isCanceled())
103: throw new OperationCanceledException();
104:
105: BinaryTypeBinding typeBinding = this .lookupEnvironment
106: .createBinaryTypeFrom(binaryType, packageBinding,
107: accessRestriction);
108: try {
109: this .remember(binaryType, typeBinding);
110: } catch (AbortCompilation e) {
111: // ignore
112: }
113: }
114:
115: /**
116: * Add an additional compilation unit.
117: * @param sourceUnit
118: */
119: public void accept(ICompilationUnit sourceUnit,
120: AccessRestriction accessRestriction) {
121: //System.out.println("Cannot accept compilation units inside the HierarchyResolver.");
122: this .lookupEnvironment.problemReporter
123: .abortDueToInternalError(new StringBuffer(
124: Messages.accept_cannot).append(
125: sourceUnit.getFileName()).toString());
126: }
127:
128: /**
129: * Add additional source types
130: * @param sourceTypes
131: * @param packageBinding
132: */
133: public void accept(ISourceType[] sourceTypes,
134: PackageBinding packageBinding,
135: AccessRestriction accessRestriction) {
136: IProgressMonitor progressMonitor = this .builder.hierarchy.progressMonitor;
137: if (progressMonitor != null && progressMonitor.isCanceled())
138: throw new OperationCanceledException();
139:
140: // find most enclosing type first (needed when explicit askForType(...) is done
141: // with a member type (e.g. p.A$B))
142: ISourceType sourceType = sourceTypes[0];
143: while (sourceType.getEnclosingType() != null)
144: sourceType = sourceType.getEnclosingType();
145:
146: // build corresponding compilation unit
147: CompilationResult result = new CompilationResult(sourceType
148: .getFileName(), 1, 1, this .options.maxProblemsPerUnit);
149: CompilationUnitDeclaration unit = SourceTypeConverter
150: .buildCompilationUnit(new ISourceType[] { sourceType }, // ignore secondary types, to improve laziness
151: SourceTypeConverter.MEMBER_TYPE, // need member types
152: // no need for field initialization
153: this .lookupEnvironment.problemReporter, result);
154:
155: // build bindings
156: if (unit != null) {
157: try {
158: this .lookupEnvironment.buildTypeBindings(unit,
159: accessRestriction);
160:
161: org.eclipse.jdt.core.ICompilationUnit cu = ((SourceTypeElementInfo) sourceType)
162: .getHandle().getCompilationUnit();
163: rememberAllTypes(unit, cu, false);
164:
165: this .lookupEnvironment
166: .completeTypeBindings(unit, true/*build constructor only*/);
167: } catch (AbortCompilation e) {
168: // missing 'java.lang' package: ignore
169: }
170: }
171: }
172:
173: /*
174: * Creates the super class handle of the given type.
175: * Returns null if the type has no super class.
176: * Adds the simple name to the hierarchy missing types if the class is not found and returns null.
177: */
178: private IType findSuperClass(IGenericType type,
179: ReferenceBinding typeBinding) {
180: ReferenceBinding super Binding = typeBinding.super class();
181:
182: if (super Binding != null) {
183: super Binding = (ReferenceBinding) super Binding.erasure();
184: if (typeBinding.isHierarchyInconsistent()) {
185: if (super Binding.problemId() == ProblemReasons.NotFound) {
186: this .hasMissingSuperClass = true;
187: this .builder.hierarchy.missingTypes.add(new String(
188: super Binding.sourceName)); // note: this could be Map$Entry
189: return null;
190: } else if ((super Binding.id == TypeIds.T_JavaLangObject)) {
191: char[] super className;
192: char separator;
193: if (type instanceof IBinaryType) {
194: super className = ((IBinaryType) type)
195: .getSuperclassName();
196: separator = '/';
197: } else if (type instanceof ISourceType) {
198: super className = ((ISourceType) type)
199: .getSuperclassName();
200: separator = '.';
201: } else if (type instanceof HierarchyType) {
202: super className = ((HierarchyType) type).super className;
203: separator = '.';
204: } else {
205: return null;
206: }
207:
208: if (super className != null) { // check whether subclass of Object due to broken hierarchy (as opposed to explicitly extending it)
209: int lastSeparator = CharOperation.lastIndexOf(
210: separator, super className);
211: char[] simpleName = lastSeparator == -1 ? super className
212: : CharOperation.subarray(
213: super className,
214: lastSeparator + 1,
215: super className.length);
216: if (!CharOperation.equals(simpleName,
217: TypeConstants.OBJECT)) {
218: this .hasMissingSuperClass = true;
219: this .builder.hierarchy.missingTypes
220: .add(new String(simpleName));
221: return null;
222: }
223: }
224: }
225: }
226: for (int t = this .typeIndex; t >= 0; t--) {
227: if (this .typeBindings[t] == super Binding) {
228: return this .builder.getHandle(this .typeModels[t],
229: super Binding);
230: }
231: }
232: }
233: return null;
234: }
235:
236: /*
237: * Returns the handles of the super interfaces of the given type.
238: * Adds the simple name to the hierarchy missing types if an interface is not found (but don't put null in the returned array)
239: */
240: private IType[] findSuperInterfaces(IGenericType type,
241: ReferenceBinding typeBinding) {
242: char[][] super InterfaceNames;
243: char separator;
244: if (type instanceof IBinaryType) {
245: super InterfaceNames = ((IBinaryType) type)
246: .getInterfaceNames();
247: separator = '/';
248: } else if (type instanceof ISourceType) {
249: ISourceType sourceType = (ISourceType) type;
250: if (sourceType.getName().length == 0) { // if anonymous type
251: if (typeBinding.super Interfaces() != null
252: && typeBinding.super Interfaces().length > 0) {
253: super InterfaceNames = new char[][] { sourceType
254: .getSuperclassName() };
255: } else {
256: super InterfaceNames = sourceType
257: .getInterfaceNames();
258: }
259: } else {
260: if (TypeDeclaration.kind(sourceType.getModifiers()) == TypeDeclaration.ANNOTATION_TYPE_DECL)
261: super InterfaceNames = new char[][] { TypeConstants.CharArray_JAVA_LANG_ANNOTATION_ANNOTATION };
262: else
263: super InterfaceNames = sourceType
264: .getInterfaceNames();
265: }
266: separator = '.';
267: } else if (type instanceof HierarchyType) {
268: HierarchyType hierarchyType = (HierarchyType) type;
269: if (hierarchyType.name.length == 0) { // if anonymous type
270: if (typeBinding.super Interfaces() != null
271: && typeBinding.super Interfaces().length > 0) {
272: super InterfaceNames = new char[][] { hierarchyType.super className };
273: } else {
274: super InterfaceNames = hierarchyType.super InterfaceNames;
275: }
276: } else {
277: super InterfaceNames = hierarchyType.super InterfaceNames;
278: }
279: separator = '.';
280: } else {
281: return null;
282: }
283:
284: ReferenceBinding[] interfaceBindings = typeBinding
285: .super Interfaces();
286: int bindingIndex = 0;
287: int bindingLength = interfaceBindings == null ? 0
288: : interfaceBindings.length;
289: int length = super InterfaceNames == null ? 0
290: : super InterfaceNames.length;
291: IType[] super interfaces = new IType[length];
292: int index = 0;
293: next: for (int i = 0; i < length; i++) {
294: char[] super InterfaceName = super InterfaceNames[i];
295: int end = super InterfaceName.length;
296:
297: // find the end of simple name
298: int genericStart = CharOperation.indexOf(
299: Signature.C_GENERIC_START, super InterfaceName);
300: if (genericStart != -1)
301: end = genericStart;
302:
303: // find the start of simple name
304: int lastSeparator = CharOperation.lastIndexOf(separator,
305: super InterfaceName, 0, end);
306: int start = lastSeparator + 1;
307:
308: // case of binary inner type -> take the last part
309: int lastDollar = CharOperation.lastIndexOf('$',
310: super InterfaceName, start);
311: if (lastDollar != -1)
312: start = lastDollar + 1;
313:
314: char[] simpleName = CharOperation.subarray(
315: super InterfaceName, start, end);
316:
317: if (bindingIndex < bindingLength) {
318: ReferenceBinding interfaceBinding = (ReferenceBinding) interfaceBindings[bindingIndex]
319: .erasure();
320:
321: // ensure that the binding corresponds to the interface defined by the user
322: if (CharOperation.equals(simpleName,
323: interfaceBinding.sourceName)) {
324: bindingIndex++;
325: for (int t = this .typeIndex; t >= 0; t--) {
326: if (this .typeBindings[t] == interfaceBinding) {
327: super interfaces[index++] = this .builder
328: .getHandle(this .typeModels[t],
329: interfaceBinding);
330: continue next;
331: }
332: }
333: }
334: }
335: this .builder.hierarchy.missingTypes.add(new String(
336: simpleName));
337: }
338: if (index != length)
339: System.arraycopy(super interfaces, 0,
340: super interfaces = new IType[index], 0, index);
341: return super interfaces;
342: }
343:
344: private void fixSupertypeBindings() {
345: for (int current = this .typeIndex; current >= 0; current--) {
346: ReferenceBinding typeBinding = this .typeBindings[current];
347:
348: if (typeBinding instanceof SourceTypeBinding) {
349: ClassScope scope = ((SourceTypeBinding) typeBinding).scope;
350: if (scope != null) {
351: TypeDeclaration typeDeclaration = scope.referenceContext;
352: TypeReference super classRef = typeDeclaration == null ? null
353: : typeDeclaration.super class;
354: TypeBinding super class = super classRef == null ? null
355: : super classRef.resolvedType;
356: if (super class instanceof ProblemReferenceBinding) {
357: super class = ((ProblemReferenceBinding) super class)
358: .closestMatch();
359: }
360: if (super class != null)
361: ((SourceTypeBinding) typeBinding).super class = (ReferenceBinding) super class;
362:
363: TypeReference[] super Interfaces = typeDeclaration == null ? null
364: : typeDeclaration.super Interfaces;
365: int length;
366: ReferenceBinding[] interfaceBindings = typeBinding
367: .super Interfaces();
368: if (super Interfaces != null
369: && (length = super Interfaces.length) > (interfaceBindings == null ? 0
370: : interfaceBindings.length)) { // check for interfaceBindings being null (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=139689)
371: interfaceBindings = new ReferenceBinding[length];
372: int index = 0;
373: for (int i = 0; i < length; i++) {
374: ReferenceBinding super Interface = (ReferenceBinding) super Interfaces[i].resolvedType;
375: if (super Interface instanceof ProblemReferenceBinding)
376: super Interface = super Interface
377: .closestMatch();
378: if (super Interface != null)
379: interfaceBindings[index++] = super Interface;
380: }
381: if (index < length)
382: System
383: .arraycopy(
384: interfaceBindings,
385: 0,
386: interfaceBindings = new ReferenceBinding[index],
387: 0, index);
388: ((SourceTypeBinding) typeBinding).super Interfaces = interfaceBindings;
389: }
390: }
391: } else if (typeBinding instanceof BinaryTypeBinding) {
392: try {
393: typeBinding.super class();
394: } catch (AbortCompilation e) {
395: // allow subsequent call to superclass() to succeed so that we don't have to catch AbortCompilation everywhere
396: ((BinaryTypeBinding) typeBinding).tagBits &= ~TagBits.HasUnresolvedSuperclass;
397: this .builder.hierarchy.missingTypes.add(new String(
398: typeBinding.super class().sourceName()));
399: this .hasMissingSuperClass = true;
400: }
401: try {
402: typeBinding.super Interfaces();
403: } catch (AbortCompilation e) {
404: // allow subsequent call to superInterfaces() to succeed so that we don't have to catch AbortCompilation everywhere
405: ((BinaryTypeBinding) typeBinding).tagBits &= ~TagBits.HasUnresolvedSuperinterfaces;
406: }
407: }
408: }
409: }
410:
411: private void remember(IGenericType suppliedType,
412: ReferenceBinding typeBinding) {
413: if (typeBinding == null)
414: return;
415:
416: if (++this .typeIndex == this .typeModels.length) {
417: System
418: .arraycopy(
419: this .typeModels,
420: 0,
421: this .typeModels = new IGenericType[this .typeIndex * 2],
422: 0, this .typeIndex);
423: System
424: .arraycopy(
425: this .typeBindings,
426: 0,
427: this .typeBindings = new ReferenceBinding[this .typeIndex * 2],
428: 0, this .typeIndex);
429: }
430: this .typeModels[this .typeIndex] = suppliedType;
431: this .typeBindings[this .typeIndex] = typeBinding;
432: }
433:
434: private void remember(IType type, ReferenceBinding typeBinding) {
435: if (((CompilationUnit) type.getCompilationUnit()).isOpen()) {
436: try {
437: IGenericType genericType = (IGenericType) ((JavaElement) type)
438: .getElementInfo();
439: remember(genericType, typeBinding);
440: } catch (JavaModelException e) {
441: // cannot happen since element is open
442: return;
443: }
444: } else {
445: if (typeBinding == null)
446: return;
447:
448: TypeDeclaration typeDeclaration = ((SourceTypeBinding) typeBinding).scope
449: .referenceType();
450:
451: // simple super class name
452: char[] super className = null;
453: TypeReference super class;
454: if ((typeDeclaration.bits & ASTNode.IsAnonymousType) != 0) {
455: super class = typeDeclaration.allocation.type;
456: } else {
457: super class = typeDeclaration.super class;
458: }
459: if (super class != null) {
460: char[][] typeName = super class.getTypeName();
461: super className = typeName == null ? null
462: : typeName[typeName.length - 1];
463: }
464:
465: // simple super interface names
466: char[][] super InterfaceNames = null;
467: TypeReference[] super Interfaces = typeDeclaration.super Interfaces;
468: if (super Interfaces != null) {
469: int length = super Interfaces.length;
470: super InterfaceNames = new char[length][];
471: for (int i = 0; i < length; i++) {
472: TypeReference super Interface = super Interfaces[i];
473: char[][] typeName = super Interface.getTypeName();
474: super InterfaceNames[i] = typeName[typeName.length - 1];
475: }
476: }
477:
478: HierarchyType hierarchyType = new HierarchyType(type,
479: typeDeclaration.name,
480: typeDeclaration.binding.modifiers, super className,
481: super InterfaceNames);
482: remember(hierarchyType, typeDeclaration.binding);
483: }
484:
485: }
486:
487: /*
488: * Remembers all type bindings defined in the given parsed unit, adding local/anonymous types if specified.
489: */
490: private void rememberAllTypes(
491: CompilationUnitDeclaration parsedUnit,
492: org.eclipse.jdt.core.ICompilationUnit cu,
493: boolean includeLocalTypes) {
494: TypeDeclaration[] types = parsedUnit.types;
495: if (types != null) {
496: for (int i = 0, length = types.length; i < length; i++) {
497: TypeDeclaration type = types[i];
498: rememberWithMemberTypes(type, cu.getType(new String(
499: type.name)));
500: }
501: }
502: if (includeLocalTypes && parsedUnit.localTypes != null) {
503: HandleFactory factory = new HandleFactory();
504: HashSet existingElements = new HashSet(
505: parsedUnit.localTypeCount);
506: HashMap knownScopes = new HashMap(parsedUnit.localTypeCount);
507: for (int i = 0; i < parsedUnit.localTypeCount; i++) {
508: LocalTypeBinding localType = parsedUnit.localTypes[i];
509: ClassScope classScope = localType.scope;
510: TypeDeclaration typeDecl = classScope.referenceType();
511: IType typeHandle = (IType) factory.createElement(
512: classScope, cu, existingElements, knownScopes);
513: rememberWithMemberTypes(typeDecl, typeHandle);
514: }
515: }
516: }
517:
518: private void rememberWithMemberTypes(TypeDeclaration typeDecl,
519: IType typeHandle) {
520: remember(typeHandle, typeDecl.binding);
521:
522: TypeDeclaration[] memberTypes = typeDecl.memberTypes;
523: if (memberTypes != null) {
524: for (int i = 0, length = memberTypes.length; i < length; i++) {
525: TypeDeclaration memberType = memberTypes[i];
526: rememberWithMemberTypes(memberType, typeHandle
527: .getType(new String(memberType.name)));
528: }
529: }
530: }
531:
532: /*
533: * Reports the hierarchy from the remembered bindings.
534: * Note that 'binaryTypeBinding' is null if focus type is a source type.
535: */
536: private void reportHierarchy(IType focus,
537: CompilationUnitDeclaration parsedUnit,
538: ReferenceBinding binaryTypeBinding) {
539:
540: // set focus type binding
541: if (focus != null) {
542: if (binaryTypeBinding != null) {
543: // binary type
544: this .focusType = binaryTypeBinding;
545: } else {
546: // source type
547: Member declaringMember = ((Member) focus)
548: .getOuterMostLocalContext();
549: if (declaringMember == null) {
550: // top level or member type
551: char[] fullyQualifiedName = focus
552: .getFullyQualifiedName().toCharArray();
553: setFocusType(CharOperation.splitOn('.',
554: fullyQualifiedName));
555: } else {
556: // anonymous or local type
557: if (parsedUnit != null) {
558: TypeDeclaration typeDecl = new ASTNodeFinder(
559: parsedUnit).findType(focus);
560: if (typeDecl != null) {
561: this .focusType = typeDecl.binding;
562: }
563: }
564: }
565: }
566: }
567:
568: // be resilient and fix super type bindings
569: fixSupertypeBindings();
570:
571: int objectIndex = -1;
572: for (int current = this .typeIndex; current >= 0; current--) {
573: ReferenceBinding typeBinding = this .typeBindings[current];
574:
575: // java.lang.Object treated at the end
576: if (typeBinding.id == TypeIds.T_JavaLangObject) {
577: objectIndex = current;
578: continue;
579: }
580:
581: IGenericType suppliedType = this .typeModels[current];
582:
583: if (!subOrSuperOfFocus(typeBinding)) {
584: continue; // ignore types outside of hierarchy
585: }
586:
587: IType super class;
588: if (typeBinding.isInterface()) { // do not connect interfaces to Object
589: super class = null;
590: } else {
591: super class = findSuperClass(suppliedType, typeBinding);
592: }
593: IType[] super interfaces = findSuperInterfaces(suppliedType,
594: typeBinding);
595:
596: this .builder.connect(suppliedType, this .builder.getHandle(
597: suppliedType, typeBinding), super class,
598: super interfaces);
599: }
600: // add java.lang.Object only if the super class is not missing
601: if (!this .hasMissingSuperClass && objectIndex > -1) {
602: IGenericType objectType = this .typeModels[objectIndex];
603: this .builder.connect(objectType, this .builder.getHandle(
604: objectType, this .typeBindings[objectIndex]), null,
605: null);
606: }
607: }
608:
609: private void reset() {
610: this .lookupEnvironment.reset();
611:
612: this .focusType = null;
613: this .super TypesOnly = false;
614: this .typeIndex = -1;
615: this .typeModels = new IGenericType[5];
616: this .typeBindings = new ReferenceBinding[5];
617: }
618:
619: /**
620: * Resolve the supertypes for the supplied source type.
621: * Inform the requestor of the resolved supertypes using:
622: * connect(ISourceType suppliedType, IGenericType superclass, IGenericType[] superinterfaces)
623: * @param suppliedType
624: */
625: public void resolve(IGenericType suppliedType) {
626: try {
627: if (suppliedType.isBinaryType()) {
628: BinaryTypeBinding binaryTypeBinding = this .lookupEnvironment
629: .cacheBinaryType(
630: (IBinaryType) suppliedType,
631: false/*don't need field and method (bug 125067)*/,
632: null /*no access restriction*/);
633: remember(suppliedType, binaryTypeBinding);
634: // We still need to add superclasses and superinterfaces bindings (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=53095)
635: int startIndex = this .typeIndex;
636: for (int i = startIndex; i <= this .typeIndex; i++) {
637: IGenericType igType = this .typeModels[i];
638: if (igType != null && igType.isBinaryType()) {
639: // fault in its hierarchy...
640: try {
641: ReferenceBinding typeBinding = this .typeBindings[i];
642: typeBinding.super class();
643: typeBinding.super Interfaces();
644: } catch (AbortCompilation e) {
645: // classpath problem for this type: ignore
646: }
647: }
648: }
649: this .super TypesOnly = true;
650: reportHierarchy(this .builder.getType(), null,
651: binaryTypeBinding);
652: } else {
653: org.eclipse.jdt.core.ICompilationUnit cu = ((SourceTypeElementInfo) suppliedType)
654: .getHandle().getCompilationUnit();
655: HashSet localTypes = new HashSet();
656: localTypes.add(cu.getPath().toString());
657: this .super TypesOnly = true;
658: resolve(new Openable[] { (Openable) cu }, localTypes,
659: null);
660: }
661: } catch (AbortCompilation e) { // ignore this exception for now since it typically means we cannot find java.lang.Object
662: } finally {
663: reset();
664: }
665: }
666:
667: /**
668: * Resolve the supertypes for the types contained in the given openables (ICompilationUnits and/or IClassFiles).
669: * Inform the requestor of the resolved supertypes for each
670: * supplied source type using:
671: * connect(ISourceType suppliedType, IGenericType superclass, IGenericType[] superinterfaces)
672: *
673: * Also inform the requestor of the supertypes of each
674: * additional requested super type which is also a source type
675: * instead of a binary type.
676: * @param openables
677: * @param localTypes
678: * @param monitor
679: */
680: public void resolve(Openable[] openables, HashSet localTypes,
681: IProgressMonitor monitor) {
682: try {
683: int openablesLength = openables.length;
684: CompilationUnitDeclaration[] parsedUnits = new CompilationUnitDeclaration[openablesLength];
685: boolean[] hasLocalType = new boolean[openablesLength];
686: org.eclipse.jdt.core.ICompilationUnit[] cus = new org.eclipse.jdt.core.ICompilationUnit[openablesLength];
687: int unitsIndex = 0;
688:
689: CompilationUnitDeclaration focusUnit = null;
690: ReferenceBinding focusBinaryBinding = null;
691: IType focus = this .builder.getType();
692: Openable focusOpenable = null;
693: if (focus != null) {
694: if (focus.isBinary()) {
695: focusOpenable = (Openable) focus.getClassFile();
696: } else {
697: focusOpenable = (Openable) focus
698: .getCompilationUnit();
699: }
700: }
701:
702: // build type bindings
703: Parser parser = new Parser(
704: this .lookupEnvironment.problemReporter, true);
705: for (int i = 0; i < openablesLength; i++) {
706: Openable openable = openables[i];
707: if (openable instanceof org.eclipse.jdt.core.ICompilationUnit) {
708: org.eclipse.jdt.core.ICompilationUnit cu = (org.eclipse.jdt.core.ICompilationUnit) openable;
709:
710: // contains a potential subtype as a local or anonymous type?
711: boolean containsLocalType = false;
712: if (localTypes == null) { // case of hierarchy on region
713: containsLocalType = true;
714: } else {
715: IPath path = cu.getPath();
716: containsLocalType = localTypes.contains(path
717: .toString());
718: }
719:
720: // build parsed unit
721: CompilationUnitDeclaration parsedUnit = null;
722: if (cu.isOpen()) {
723: // create parsed unit from source element infos
724: CompilationResult result = new CompilationResult(
725: ((ICompilationUnit) cu).getFileName(),
726: i, openablesLength,
727: this .options.maxProblemsPerUnit);
728: SourceTypeElementInfo[] typeInfos = null;
729: try {
730: IType[] topLevelTypes = cu.getTypes();
731: int topLevelLength = topLevelTypes.length;
732: if (topLevelLength == 0)
733: continue; // empty cu: no need to parse (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=65677)
734: typeInfos = new SourceTypeElementInfo[topLevelLength];
735: for (int j = 0; j < topLevelLength; j++) {
736: IType topLevelType = topLevelTypes[j];
737: typeInfos[j] = (SourceTypeElementInfo) ((JavaElement) topLevelType)
738: .getElementInfo();
739: }
740: } catch (JavaModelException e) {
741: // types/cu exist since cu is opened
742: }
743: int flags = !containsLocalType ? SourceTypeConverter.MEMBER_TYPE
744: : SourceTypeConverter.FIELD_AND_METHOD
745: | SourceTypeConverter.MEMBER_TYPE
746: | SourceTypeConverter.LOCAL_TYPE;
747: parsedUnit = SourceTypeConverter
748: .buildCompilationUnit(
749: typeInfos,
750: flags,
751: this .lookupEnvironment.problemReporter,
752: result);
753: if (containsLocalType)
754: parsedUnit.bits |= ASTNode.HasAllMethodBodies;
755: } else {
756: // create parsed unit from file
757: IFile file = (IFile) cu.getResource();
758: ICompilationUnit sourceUnit = this .builder
759: .createCompilationUnitFromPath(
760: openable, file);
761:
762: CompilationResult unitResult = new CompilationResult(
763: sourceUnit, i, openablesLength,
764: this .options.maxProblemsPerUnit);
765: parsedUnit = parser.dietParse(sourceUnit,
766: unitResult);
767: }
768:
769: if (parsedUnit != null) {
770: hasLocalType[unitsIndex] = containsLocalType;
771: cus[unitsIndex] = cu;
772: parsedUnits[unitsIndex++] = parsedUnit;
773: try {
774: this .lookupEnvironment
775: .buildTypeBindings(parsedUnit, null /*no access restriction*/);
776: if (openable.equals(focusOpenable)) {
777: focusUnit = parsedUnit;
778: }
779: } catch (AbortCompilation e) {
780: // classpath problem for this type: ignore
781: }
782: }
783: } else {
784: // cache binary type binding
785: ClassFile classFile = (ClassFile) openable;
786: IBinaryType binaryType = null;
787: if (classFile.isOpen()) {
788: // create binary type from info
789: IType type = classFile.getType();
790: try {
791: binaryType = (IBinaryType) ((JavaElement) type)
792: .getElementInfo();
793: } catch (JavaModelException e) {
794: // type exists since class file is opened
795: }
796: } else {
797: // create binary type from file
798: if (classFile.getPackageFragmentRoot()
799: .isArchive()) {
800: binaryType = this .builder
801: .createInfoFromClassFileInJar(classFile);
802: } else {
803: IResource file = classFile.getResource();
804: binaryType = this .builder
805: .createInfoFromClassFile(classFile,
806: file);
807: }
808: }
809: if (binaryType != null) {
810: try {
811: BinaryTypeBinding binaryTypeBinding = this .lookupEnvironment
812: .cacheBinaryType(
813: binaryType,
814: false/*don't need field and method (bug 125067)*/,
815: null /*no access restriction*/);
816: remember(binaryType, binaryTypeBinding);
817: if (openable.equals(focusOpenable)) {
818: focusBinaryBinding = binaryTypeBinding;
819: }
820: } catch (AbortCompilation e) {
821: // classpath problem for this type: ignore
822: }
823: }
824: }
825: }
826:
827: for (int i = 0; i <= this .typeIndex; i++) {
828: IGenericType suppliedType = this .typeModels[i];
829: if (suppliedType != null && suppliedType.isBinaryType()) {
830: // fault in its hierarchy...
831: try {
832: ReferenceBinding typeBinding = this .typeBindings[i];
833: typeBinding.super class();
834: typeBinding.super Interfaces();
835: } catch (AbortCompilation e) {
836: // classpath problem for this type: ignore
837: }
838: }
839: }
840:
841: // complete type bindings (ie. connect super types)
842: for (int i = 0; i < unitsIndex; i++) {
843: CompilationUnitDeclaration parsedUnit = parsedUnits[i];
844: if (parsedUnit != null) {
845: try {
846: boolean containsLocalType = hasLocalType[i];
847: if (containsLocalType) { // NB: no-op if method bodies have been already parsed
848: parser.getMethodBodies(parsedUnit);
849: }
850: // complete type bindings and build fields and methods only for local types
851: // (in this case the constructor is needed when resolving local types)
852: // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=145333)
853: this .lookupEnvironment.completeTypeBindings(
854: parsedUnit, containsLocalType);
855: } catch (AbortCompilation e) {
856: // classpath problem for this type: don't try to resolve (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=49809)
857: hasLocalType[i] = false;
858: }
859: }
860: worked(monitor, 1);
861: }
862:
863: // remember type bindings
864: for (int i = 0; i < unitsIndex; i++) {
865: CompilationUnitDeclaration parsedUnit = parsedUnits[i];
866: if (parsedUnit != null) {
867: boolean containsLocalType = hasLocalType[i];
868: if (containsLocalType) {
869: parsedUnit.scope.faultInTypes();
870: parsedUnit.resolve();
871: }
872:
873: rememberAllTypes(parsedUnit, cus[i],
874: containsLocalType);
875: }
876: }
877:
878: // if no potential subtype was a real subtype of the binary focus type, no need to go further
879: // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=54043)
880: if (focusBinaryBinding == null && focus != null
881: && focus.isBinary()) {
882: char[] fullyQualifiedName = focus
883: .getFullyQualifiedName().toCharArray();
884: focusBinaryBinding = this .lookupEnvironment
885: .getCachedType(CharOperation.splitOn('.',
886: fullyQualifiedName));
887: if (focusBinaryBinding == null)
888: return;
889: }
890:
891: reportHierarchy(focus, focusUnit, focusBinaryBinding);
892:
893: } catch (ClassCastException e) { // work-around for 1GF5W1S - can happen in case duplicates are fed to the hierarchy with binaries hiding sources
894: } catch (AbortCompilation e) { // ignore this exception for now since it typically means we cannot find java.lang.Object
895: if (TypeHierarchy.DEBUG)
896: e.printStackTrace();
897: } finally {
898: reset();
899: }
900: }
901:
902: private void setEnvironment(LookupEnvironment lookupEnvironment,
903: HierarchyBuilder builder) {
904: this .lookupEnvironment = lookupEnvironment;
905: this .builder = builder;
906:
907: this .typeIndex = -1;
908: this .typeModels = new IGenericType[5];
909: this .typeBindings = new ReferenceBinding[5];
910: }
911:
912: /*
913: * Set the focus type (ie. the type that this resolver is computing the hierarch for.
914: * Returns the binding of this focus type or null if it could not be found.
915: */
916: public ReferenceBinding setFocusType(char[][] compoundName) {
917: if (compoundName == null || this .lookupEnvironment == null)
918: return null;
919: this .focusType = this .lookupEnvironment
920: .getCachedType(compoundName);
921: if (this .focusType == null) {
922: this .focusType = this .lookupEnvironment
923: .askForType(compoundName);
924: }
925: return this .focusType;
926: }
927:
928: public boolean subOrSuperOfFocus(ReferenceBinding typeBinding) {
929: if (this .focusType == null)
930: return true; // accept all types (case of hierarchy in a region)
931: try {
932: if (this .subTypeOfType(this .focusType, typeBinding))
933: return true;
934: if (!this .super TypesOnly
935: && this .subTypeOfType(typeBinding, this .focusType))
936: return true;
937: } catch (AbortCompilation e) {
938: // unresolved superclass/superinterface -> ignore
939: }
940: return false;
941: }
942:
943: private boolean subTypeOfType(ReferenceBinding subType,
944: ReferenceBinding typeBinding) {
945: if (typeBinding == null || subType == null)
946: return false;
947: if (subType == typeBinding)
948: return true;
949: ReferenceBinding super class = subType.super class();
950: if (super class != null)
951: super class = (ReferenceBinding) super class.erasure();
952: // if (superclass != null && superclass.id == TypeIds.T_JavaLangObject && subType.isHierarchyInconsistent()) return false;
953: if (this .subTypeOfType(super class, typeBinding))
954: return true;
955: ReferenceBinding[] super Interfaces = subType.super Interfaces();
956: if (super Interfaces != null) {
957: for (int i = 0, length = super Interfaces.length; i < length; i++) {
958: ReferenceBinding super Interface = (ReferenceBinding) super Interfaces[i]
959: .erasure();
960: if (this .subTypeOfType(super Interface, typeBinding))
961: return true;
962: }
963: }
964: return false;
965: }
966:
967: protected void worked(IProgressMonitor monitor, int work) {
968: if (monitor != null) {
969: if (monitor.isCanceled()) {
970: throw new OperationCanceledException();
971: } else {
972: monitor.worked(work);
973: }
974: }
975: }
976: }
|