package org.eclipse.jdt.internal.compiler; | |
/* | |
* (c) Copyright IBM Corp. 2000, 2001. | |
* All Rights Reserved. | |
*/ | |
/** | |
* This is the public entry point to resolve type hierarchies. | |
* | |
* When requesting additional types from the name environment, the resolver | |
* accepts all forms (binary, source & compilation unit) for additional types. | |
* | |
* Side notes: Binary types already know their resolved supertypes so this | |
* only makes sense for source types. Even though the compiler finds all binary | |
* types to complete the hierarchy of a given source type, is there any reason | |
* why the requestor should be informed that binary type X subclasses Y & | |
* implements I & J? | |
*/ | |
import org.eclipse.jdt.internal.compiler.env.*; | |
import org.eclipse.jdt.internal.compiler.impl.*; | |
import org.eclipse.jdt.internal.compiler.ast.*; | |
import org.eclipse.jdt.internal.compiler.lookup.*; | |
import org.eclipse.jdt.internal.compiler.parser.*; | |
import org.eclipse.jdt.internal.compiler.problem.*; | |
import org.eclipse.jdt.internal.compiler.util.*; | |
import java.util.Locale; | |
import java.util.Map; | |
public class HierarchyResolver implements ITypeRequestor { | |
IHierarchyRequestor requestor; | |
LookupEnvironment lookupEnvironment; | |
private int typeIndex; | |
private IGenericType[] typeModels; | |
private ReferenceBinding[] typeBindings; | |
private ReferenceBinding focusType; | |
private CompilerOptions options; | |
public HierarchyResolver( | |
INameEnvironment nameEnvironment, | |
IErrorHandlingPolicy policy, | |
Map settings, | |
IHierarchyRequestor requestor, | |
IProblemFactory problemFactory) { | |
// create a problem handler given a handling policy | |
options = settings == null ? new CompilerOptions() : new CompilerOptions(settings); | |
ProblemReporter problemReporter = new ProblemReporter(policy, options, problemFactory); | |
this.lookupEnvironment = new LookupEnvironment(this, options, problemReporter, nameEnvironment); | |
this.requestor = requestor; | |
this.typeIndex = -1; | |
this.typeModels = new IGenericType[5]; | |
this.typeBindings = new ReferenceBinding[5]; | |
} | |
public HierarchyResolver(INameEnvironment nameEnvironment, Map settings, IHierarchyRequestor requestor, IProblemFactory problemFactory) { | |
this( | |
nameEnvironment, | |
DefaultErrorHandlingPolicies.exitAfterAllProblems(), | |
settings, | |
requestor, | |
problemFactory); | |
} | |
/** | |
* Add an additional binary type | |
*/ | |
public void accept(IBinaryType binaryType, PackageBinding packageBinding) { | |
BinaryTypeBinding typeBinding = lookupEnvironment.createBinaryTypeFrom(binaryType, packageBinding); | |
remember(binaryType, typeBinding); | |
} | |
/** | |
* Add an additional compilation unit. | |
*/ | |
public void accept(ICompilationUnit sourceUnit) { | |
//System.out.println("Cannot accept compilation units inside the HierarchyResolver."); | |
lookupEnvironment.problemReporter.abortDueToInternalError( | |
new StringBuffer(Util.bind("accept.cannot")) //$NON-NLS-1$ | |
.append(sourceUnit.getFileName()) | |
.toString()); | |
} | |
/** | |
* Add additional source types | |
*/ | |
public void accept(ISourceType[] sourceTypes, PackageBinding packageBinding) { | |
CompilationResult result = new CompilationResult(sourceTypes[0].getFileName(), 1, 1); | |
CompilationUnitDeclaration unit = | |
SourceTypeConverter.buildCompilationUnit(sourceTypes, false, true, lookupEnvironment.problemReporter, result); | |
if (unit != null) { | |
lookupEnvironment.buildTypeBindings(unit); | |
for (int i = 0, length = sourceTypes.length; i < length; i++) { | |
rememberWithMemberTypes(sourceTypes[i], unit.types[i].binding); | |
} | |
lookupEnvironment.completeTypeBindings(unit, false); | |
} | |
} | |
private void remember(IGenericType suppliedType, ReferenceBinding typeBinding) { | |
if (typeBinding == null) return; | |
if (!subOrSuperOfFocus(typeBinding)) { | |
return; // ignore types outside of hierarchy | |
} | |
if (++typeIndex == typeModels.length) { | |
System.arraycopy(typeModels, 0, typeModels = new IGenericType[typeIndex * 2], 0, typeIndex); | |
System.arraycopy(typeBindings, 0, typeBindings = new ReferenceBinding[typeIndex * 2], 0, typeIndex); | |
} | |
typeModels[typeIndex] = suppliedType; | |
typeBindings[typeIndex] = typeBinding; | |
} | |
private void rememberWithMemberTypes(TypeDeclaration typeDeclaration, HierarchyType enclosingType, ICompilationUnit unit) { | |
if (typeDeclaration.binding == null) return; | |
HierarchyType hierarchyType = new HierarchyType( | |
enclosingType, | |
!typeDeclaration.isInterface(), | |
typeDeclaration.name, | |
typeDeclaration.binding.modifiers, | |
unit); | |
remember(hierarchyType, typeDeclaration.binding); | |
// propagate into member types | |
if (typeDeclaration.memberTypes == null) return; | |
MemberTypeDeclaration[] memberTypes = typeDeclaration.memberTypes; | |
for (int i = 0, max = memberTypes.length; i < max; i++){ | |
rememberWithMemberTypes(memberTypes[i], hierarchyType, unit); | |
} | |
} | |
private void rememberWithMemberTypes(ISourceType suppliedType, ReferenceBinding typeBinding) { | |
if (typeBinding == null) return; | |
remember(suppliedType, typeBinding); | |
ISourceType[] memberTypes = suppliedType.getMemberTypes(); | |
if (memberTypes == null) return; | |
for (int m = memberTypes.length; --m >= 0;) { | |
ISourceType memberType = memberTypes[m]; | |
rememberWithMemberTypes(memberType, typeBinding.getMemberType(memberType.getName())); | |
} | |
} | |
private void reportHierarchy() { | |
// ensure each binary type knows its supertypes before reporting the hierarchy | |
int problemLength = typeIndex+1; | |
boolean[] typesWithProblem = new boolean[problemLength]; | |
for (int current = 0; current <= typeIndex; current++) { // typeIndex may continue to grow | |
ReferenceBinding typeBinding = typeBindings[current]; | |
if (typeBinding.isBinaryBinding()) { | |
// fault in its hierarchy... | |
try { | |
typeBinding.superclass(); | |
typeBinding.superInterfaces(); | |
} catch (AbortCompilation e) { | |
if (current >= problemLength) { | |
System.arraycopy(typesWithProblem, 0, typesWithProblem = new boolean[current+1], 0, problemLength); | |
problemLength = current+1; | |
} | |
typesWithProblem[current] = true; | |
} | |
} | |
} | |
for (int current = typeIndex; current >= 0; current--) { | |
IGenericType suppliedType = typeModels[current]; | |
ReferenceBinding typeBinding = typeBindings[current]; | |
if (current < problemLength && typesWithProblem[current]) continue; | |
ReferenceBinding superBinding = typeBinding.superclass(); | |
IGenericType superclass = null; | |
if (superBinding != null) { | |
for (int t = typeIndex; t >= 0; t--) { | |
if (typeBindings[t] == superBinding) { | |
superclass = typeModels[t]; | |
break; | |
} | |
} | |
} | |
ReferenceBinding[] interfaceBindings = typeBinding.superInterfaces(); | |
int length = interfaceBindings.length; | |
IGenericType[] superinterfaces = new IGenericType[length]; | |
next : for (int i = 0; i < length; i++) { | |
ReferenceBinding interfaceBinding = interfaceBindings[i]; | |
for (int t = typeIndex; t >= 0; t--) { | |
if (typeBindings[t] == interfaceBinding) { | |
superinterfaces[i] = typeModels[t]; | |
continue next; | |
} | |
} | |
} | |
if (typeBinding.isInterface()){ // do not connect interfaces to Object | |
superclass = null; | |
} | |
requestor.connect(suppliedType, superclass, superinterfaces); | |
} | |
} | |
private void reset(){ | |
lookupEnvironment.reset(); | |
this.typeIndex = -1; | |
this.typeModels = new IGenericType[5]; | |
this.typeBindings = new ReferenceBinding[5]; | |
} | |
/** | |
* Resolve the supertypes for the supplied source types. | |
* Inform the requestor of the resolved supertypes for each | |
* supplied source type using: | |
* connect(ISourceType suppliedType, IGenericType superclass, IGenericType[] superinterfaces) | |
* | |
* Also inform the requestor of the supertypes of each | |
* additional requested super type which is also a source type | |
* instead of a binary type. | |
*/ | |
public void resolve(IGenericType[] suppliedTypes) { | |
resolve(suppliedTypes, null); | |
} | |
/** | |
* Resolve the supertypes for the supplied source types. | |
* Inform the requestor of the resolved supertypes for each | |
* supplied source type using: | |
* connect(ISourceType suppliedType, IGenericType superclass, IGenericType[] superinterfaces) | |
* | |
* Also inform the requestor of the supertypes of each | |
* additional requested super type which is also a source type | |
* instead of a binary type. | |
*/ | |
public void resolve(IGenericType[] suppliedTypes, ICompilationUnit[] sourceUnits) { | |
try { | |
int suppliedLength = suppliedTypes == null ? 0 : suppliedTypes.length; | |
int sourceLength = sourceUnits == null ? 0 : sourceUnits.length; | |
CompilationUnitDeclaration[] units = new CompilationUnitDeclaration[suppliedLength + sourceLength]; | |
// build type bindings | |
for (int i = 0; i < suppliedLength; i++) { | |
if (suppliedTypes[i].isBinaryType()) { | |
IBinaryType binaryType = (IBinaryType) suppliedTypes[i]; | |
try { | |
remember(binaryType, lookupEnvironment.cacheBinaryType(binaryType, false)); | |
} catch (AbortCompilation e) { | |
// classpath problem for this type: ignore | |
} | |
} else { | |
// must start with the top level type | |
ISourceType topLevelType = (ISourceType) suppliedTypes[i]; | |
while (topLevelType.getEnclosingType() != null) | |
topLevelType = topLevelType.getEnclosingType(); | |
CompilationResult result = new CompilationResult(topLevelType.getFileName(), i, suppliedLength); | |
units[i] = SourceTypeConverter.buildCompilationUnit(new ISourceType[]{topLevelType}, false, true, lookupEnvironment.problemReporter, result); | |
if (units[i] != null) { | |
try { | |
lookupEnvironment.buildTypeBindings(units[i]); | |
} catch (AbortCompilation e) { | |
// classpath problem for this type: ignore | |
} | |
} | |
} | |
} | |
for (int i = 0; i < sourceLength; i++){ | |
ICompilationUnit sourceUnit = sourceUnits[i]; | |
CompilationResult unitResult = new CompilationResult(sourceUnit, suppliedLength+i, suppliedLength+sourceLength); | |
Parser parser = new Parser(lookupEnvironment.problemReporter, true, options.assertMode); | |
CompilationUnitDeclaration parsedUnit = parser.dietParse(sourceUnit, unitResult); | |
if (parsedUnit != null) { | |
units[suppliedLength+i] = parsedUnit; | |
lookupEnvironment.buildTypeBindings(parsedUnit); | |
} | |
} | |
// complete type bindings (ie. connect super types) and remember them | |
for (int i = 0; i < suppliedLength; i++) { | |
if (!suppliedTypes[i].isBinaryType()) { // note that binary types have already been remembered above | |
CompilationUnitDeclaration parsedUnit = units[i]; | |
if (parsedUnit != null) { | |
// must start with the top level type | |
ISourceType topLevelType = (ISourceType) suppliedTypes[i]; | |
suppliedTypes[i] = null; // no longer needed pass this point | |
while (topLevelType.getEnclosingType() != null) | |
topLevelType = topLevelType.getEnclosingType(); | |
try { | |
lookupEnvironment.completeTypeBindings(parsedUnit, false); | |
rememberWithMemberTypes(topLevelType, parsedUnit.types[0].binding); | |
} catch (AbortCompilation e) { | |
// classpath problem for this type: ignore | |
} | |
} | |
} | |
} | |
for (int i = 0; i < sourceLength; i++) { | |
CompilationUnitDeclaration parsedUnit = units[suppliedLength+i]; | |
if (parsedUnit != null) { | |
lookupEnvironment.completeTypeBindings(parsedUnit, false); | |
int typeCount = parsedUnit.types == null ? 0 : parsedUnit.types.length; | |
ICompilationUnit sourceUnit = sourceUnits[i]; | |
sourceUnits[i] = null; // no longer needed pass this point | |
for (int j = 0; j < typeCount; j++){ | |
rememberWithMemberTypes(parsedUnit.types[j], null, sourceUnit); | |
} | |
} | |
} | |
reportHierarchy(); | |
} catch (ClassCastException e){ // work-around for 1GF5W1S - can happen in case duplicates are fed to the hierarchy with binaries hiding sources | |
} catch (AbortCompilation e) { // ignore this exception for now since it typically means we cannot find java.lang.Object | |
} finally { | |
reset(); | |
} | |
} | |
/** | |
* Resolve the supertypes for the supplied source type. | |
* Inform the requestor of the resolved supertypes using: | |
* connect(ISourceType suppliedType, IGenericType superclass, IGenericType[] superinterfaces) | |
*/ | |
public void resolve(IGenericType suppliedType) { | |
try { | |
if (suppliedType.isBinaryType()) { | |
remember(suppliedType, lookupEnvironment.cacheBinaryType((IBinaryType) suppliedType)); | |
} else { | |
// must start with the top level type | |
ISourceType topLevelType = (ISourceType) suppliedType; | |
while (topLevelType.getEnclosingType() != null) | |
topLevelType = topLevelType.getEnclosingType(); | |
CompilationResult result = new CompilationResult(topLevelType.getFileName(), 1, 1); | |
CompilationUnitDeclaration unit = | |
SourceTypeConverter.buildCompilationUnit(new ISourceType[]{topLevelType}, false, true, lookupEnvironment.problemReporter, result); | |
if (unit != null) { | |
lookupEnvironment.buildTypeBindings(unit); | |
rememberWithMemberTypes(topLevelType, unit.types[0].binding); | |
lookupEnvironment.completeTypeBindings(unit, false); | |
} | |
} | |
reportHierarchy(); | |
} catch (AbortCompilation e) { // ignore this exception for now since it typically means we cannot find java.lang.Object | |
} finally { | |
reset(); | |
} | |
} | |
/** | |
* Set the focus type (ie. the type that this resolver is computing the hierarch for. | |
* Returns the binding of this focus type or null if it could not be found. | |
*/ | |
public ReferenceBinding setFocusType(char[][] compoundName) { | |
if (compoundName == null || this.lookupEnvironment == null) return null; | |
this.focusType = this.lookupEnvironment.askForType(compoundName); | |
if (this.focusType == null) return null; | |
/* All siblings of the focus type were added (since this.focusType == null). | |
Remove the ones that are not part of the hierarchy | |
*/ | |
int typeIndex = this.typeIndex; | |
this.typeIndex = -1; | |
ReferenceBinding[] typeBindings = this.typeBindings; | |
this.typeBindings = new ReferenceBinding[5]; | |
IGenericType[] typeModels = this.typeModels; | |
this.typeModels = new IGenericType[5]; | |
for (int i = 0; i <= typeIndex; i++) { | |
this.remember(typeModels[i], typeBindings[i]); // will skip types not part of the hierarchy | |
} | |
return this.focusType; | |
} | |
private boolean subOrSuperOfFocus(ReferenceBinding typeBinding) { | |
if (this.focusType == null) return true; // accept all types (case of hierarchy in a region) | |
if (this.subTypeOfType(this.focusType, typeBinding)) return true; | |
if (this.subTypeOfType(typeBinding, this.focusType)) return true; | |
return false; | |
} | |
private boolean subTypeOfType(ReferenceBinding subType, ReferenceBinding typeBinding) { | |
if (typeBinding == null || subType == null) return false; | |
if (subType == typeBinding) return true; | |
if (this.subTypeOfType(subType.superclass(), typeBinding)) return true; | |
ReferenceBinding[] superInterfaces = subType.superInterfaces(); | |
if (superInterfaces != null) { | |
for (int i = 0, length = superInterfaces.length; i < length; i++) { | |
if (this.subTypeOfType(superInterfaces[i], typeBinding)) return true; | |
} | |
} | |
return false; | |
} | |
} |