/*******************************************************************************
* Copyright (c) 2000, 2011 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.wst.jsdt.internal.core.hierarchy;
/**
* 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 java.util.HashSet;
import java.util.Map;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.wst.jsdt.core.IType;
import org.eclipse.wst.jsdt.core.JavaScriptModelException;
import org.eclipse.wst.jsdt.core.compiler.CharOperation;
import org.eclipse.wst.jsdt.core.infer.InferredType;
import org.eclipse.wst.jsdt.internal.compiler.CompilationResult;
import org.eclipse.wst.jsdt.internal.compiler.DefaultErrorHandlingPolicies;
import org.eclipse.wst.jsdt.internal.compiler.IErrorHandlingPolicy;
import org.eclipse.wst.jsdt.internal.compiler.IProblemFactory;
import org.eclipse.wst.jsdt.internal.compiler.ast.ASTNode;
import org.eclipse.wst.jsdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.wst.jsdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.wst.jsdt.internal.compiler.ast.TypeReference;
import org.eclipse.wst.jsdt.internal.compiler.env.AccessRestriction;
import org.eclipse.wst.jsdt.internal.compiler.env.IBinaryType;
import org.eclipse.wst.jsdt.internal.compiler.env.ICompilationUnit;
import org.eclipse.wst.jsdt.internal.compiler.env.IGenericType;
import org.eclipse.wst.jsdt.internal.compiler.env.INameEnvironment;
import org.eclipse.wst.jsdt.internal.compiler.env.ISourceType;
import org.eclipse.wst.jsdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.wst.jsdt.internal.compiler.impl.ITypeRequestor;
import org.eclipse.wst.jsdt.internal.compiler.impl.ITypeRequestor2;
import org.eclipse.wst.jsdt.internal.compiler.lookup.BinaryTypeBinding;
import org.eclipse.wst.jsdt.internal.compiler.lookup.ClassScope;
import org.eclipse.wst.jsdt.internal.compiler.lookup.LookupEnvironment;
import org.eclipse.wst.jsdt.internal.compiler.lookup.PackageBinding;
import org.eclipse.wst.jsdt.internal.compiler.lookup.ProblemReasons;
import org.eclipse.wst.jsdt.internal.compiler.lookup.ProblemReferenceBinding;
import org.eclipse.wst.jsdt.internal.compiler.lookup.ReferenceBinding;
import org.eclipse.wst.jsdt.internal.compiler.lookup.SourceTypeBinding;
import org.eclipse.wst.jsdt.internal.compiler.lookup.TagBits;
import org.eclipse.wst.jsdt.internal.compiler.lookup.TypeBinding;
import org.eclipse.wst.jsdt.internal.compiler.lookup.TypeConstants;
import org.eclipse.wst.jsdt.internal.compiler.lookup.TypeIds;
import org.eclipse.wst.jsdt.internal.compiler.parser.Parser;
import org.eclipse.wst.jsdt.internal.compiler.parser.SourceTypeConverter;
import org.eclipse.wst.jsdt.internal.compiler.problem.AbortCompilation;
import org.eclipse.wst.jsdt.internal.compiler.problem.ProblemReporter;
import org.eclipse.wst.jsdt.internal.compiler.util.HashtableOfObject;
import org.eclipse.wst.jsdt.internal.core.ClassFile;
import org.eclipse.wst.jsdt.internal.core.CompilationUnit;
import org.eclipse.wst.jsdt.internal.core.JavaElement;
import org.eclipse.wst.jsdt.internal.core.Member;
import org.eclipse.wst.jsdt.internal.core.Openable;
import org.eclipse.wst.jsdt.internal.core.SourceTypeElementInfo;
import org.eclipse.wst.jsdt.internal.core.util.ASTNodeFinder;
import org.eclipse.wst.jsdt.internal.oaametadata.LibraryAPIs;
public class HierarchyResolver implements ITypeRequestor, ITypeRequestor2 {
private ReferenceBinding focusType;
private boolean superTypesOnly;
private boolean hasMissingSuperClass;
LookupEnvironment lookupEnvironment;
private CompilerOptions options;
HierarchyBuilder builder;
private ReferenceBinding[] typeBindings;
HashtableOfObject parsedUnits;
HashSet processedUnits=new HashSet();
private int typeIndex;
private IGenericType[] typeModels;
public HierarchyResolver(INameEnvironment nameEnvironment, Map settings, HierarchyBuilder builder, IProblemFactory problemFactory) {
// create a problem handler with the 'exit after all problems' handling policy
this.options = new CompilerOptions(settings);
IErrorHandlingPolicy policy = DefaultErrorHandlingPolicies.exitAfterAllProblems();
ProblemReporter problemReporter = new ProblemReporter(policy, this.options, problemFactory);
this.setEnvironment(
new LookupEnvironment(this, this.options, problemReporter, nameEnvironment),
builder);
}
public HierarchyResolver(LookupEnvironment lookupEnvironment, HierarchyBuilder builder) {
this.setEnvironment(lookupEnvironment, builder);
}
/**
* Add an additional binary type
* @param binaryType
* @param packageBinding
*/
public void accept(IBinaryType binaryType, PackageBinding packageBinding, AccessRestriction accessRestriction) {
// IProgressMonitor progressMonitor = this.builder.hierarchy.progressMonitor;
// if (progressMonitor != null && progressMonitor.isCanceled())
// throw new OperationCanceledException();
// BinaryTypeBinding typeBinding = this.lookupEnvironment.createBinaryTypeFrom(binaryType, packageBinding, accessRestriction);
// try {
// this.remember(binaryType, typeBinding);
// } catch (AbortCompilation e) {
// // ignore
// }
}
/**
* Add an additional compilation unit.
* @param sourceUnit
*/
public void accept(ICompilationUnit sourceUnit, AccessRestriction accessRestriction) {
accept(sourceUnit, new char[0][0], accessRestriction);
}
public void accept(ICompilationUnit sourceUnit, char[][] typeNames,
AccessRestriction accessRestriction) {
// System.out.println("Cannot accept compilation units inside the HierarchyResolver.");
// this.lookupEnvironment.problemReporter.abortDueToInternalError(
// new StringBuffer(Messages.accept_cannot)
// .append(sourceUnit.getFileName())
// .toString());
if (typeNames.length == 0 && this.processedUnits.contains(sourceUnit))
return;
CompilationResult result = new CompilationResult(sourceUnit, 1, 1,
this.options.maxProblemsPerUnit);
if (parsedUnits == null)
parsedUnits = new HashtableOfObject();
CompilationUnitDeclaration parsedUnit = (CompilationUnitDeclaration) parsedUnits.get(sourceUnit.getFileName());
if (parsedUnit == null) {
if (typeNames.length == 0)
this.processedUnits.add(sourceUnit);
Parser parser = new Parser(this.lookupEnvironment.problemReporter, true);
parsedUnit = parser.dietParse(sourceUnit, result);
parser.inferTypes(parsedUnit, this.options);
parsedUnits.put(sourceUnit.getFileName(), parsedUnit);
}
if (parsedUnit != null) {
try {
this.lookupEnvironment.buildTypeBindings(parsedUnit, typeNames, accessRestriction);
// org.eclipse.wst.jsdt.core.IJavaScriptUnit cu =
// ((SourceTypeElementInfo)sourceType).getHandle().getCompilationUnit();
rememberAllTypes(parsedUnit, sourceUnit, false);
this.lookupEnvironment.completeTypeBindings(parsedUnit, typeNames, true/*
* build constructor
* only
*/);
} catch (AbortCompilation e) {
// missing 'java.lang' package: ignore
}
}
}
public void accept(LibraryAPIs libraryMetaData)
{
lookupEnvironment.buildTypeBindings(libraryMetaData);
}
/**
* Add additional source types
* @param sourceTypes
* @param packageBinding
*/
public void accept(ISourceType[] sourceTypes, PackageBinding packageBinding, AccessRestriction accessRestriction) {
// find most enclosing type first (needed when explicit askForType(...) is done
// with a member type (e.g. p.A$B))
IProgressMonitor progressMonitor = this.builder.hierarchy.progressMonitor;
if (progressMonitor != null && progressMonitor.isCanceled())
throw new OperationCanceledException();
ISourceType sourceType = sourceTypes[0];
while (sourceType.getEnclosingType() != null)
sourceType = sourceType.getEnclosingType();
// build corresponding compilation unit
CompilationResult result = new CompilationResult(sourceType.getFileName(), sourceType.getPackageName(), 1, 1, this.options.maxProblemsPerUnit);
CompilationUnitDeclaration unit =
SourceTypeConverter.buildCompilationUnit(
new ISourceType[] {sourceType}, // ignore secondary types, to improve laziness
SourceTypeConverter.MEMBER_TYPE, // need member types
// no need for field initialization
this.lookupEnvironment.problemReporter,
result);
// build bindings
if (unit != null) {
try {
this.lookupEnvironment.buildTypeBindings(unit, accessRestriction);
org.eclipse.wst.jsdt.core.IJavaScriptUnit cu = ((SourceTypeElementInfo)sourceType).getHandle().getJavaScriptUnit();
rememberAllTypes(unit, cu, false);
this.lookupEnvironment.completeTypeBindings(unit, true/*build constructor only*/);
} catch (AbortCompilation e) {
// missing 'java.lang' package: ignore
}
}
}
/*
* Creates the super class handle of the given type.
* Returns null if the type has no super class.
* Adds the simple name to the hierarchy missing types if the class is not found and returns null.
*/
private IType findSuperClass(IGenericType type, ReferenceBinding typeBinding) {
ReferenceBinding superBinding = typeBinding.superclass();
if (superBinding != null) {
if (typeBinding.isHierarchyInconsistent()) {
if (superBinding.problemId() == ProblemReasons.NotFound) {
this.hasMissingSuperClass = true;
this.builder.hierarchy.missingTypes.add(new String(superBinding.sourceName)); // note: this could be Map$Entry
return null;
} else if ((superBinding.id == TypeIds.T_JavaLangObject)) {
char[] superclassName;
char separator;
if (type instanceof IBinaryType) {
superclassName = ((IBinaryType)type).getSuperclassName();
separator = '/';
} else if (type instanceof ISourceType) {
superclassName = ((ISourceType)type).getSuperclassName();
separator = '.';
} else if (type instanceof HierarchyType) {
superclassName = ((HierarchyType)type).superclassName;
separator = '.';
} else {
return null;
}
if (superclassName != null) { // check whether subclass of Object due to broken hierarchy (as opposed to explicitly extending it)
int lastSeparator = CharOperation.lastIndexOf(separator, superclassName);
char[] simpleName = lastSeparator == -1 ? superclassName : CharOperation.subarray(superclassName, lastSeparator+1, superclassName.length);
if (!CharOperation.equals(simpleName, TypeConstants.OBJECT)) {
this.hasMissingSuperClass = true;
this.builder.hierarchy.missingTypes.add(new String(simpleName));
return null;
}
}
}
}
for (int t = this.typeIndex; t >= 0; t--) {
if (this.typeBindings[t] == superBinding) {
return this.builder.getHandle(this.typeModels[t], superBinding);
}
}
}
return null;
}
private void fixSupertypeBindings() {
for (int current = this.typeIndex; current >= 0; current--) {
ReferenceBinding typeBinding = this.typeBindings[current];
if (typeBinding instanceof SourceTypeBinding) {
ClassScope scope = (ClassScope)((SourceTypeBinding) typeBinding).scope;
if (scope != null) {
TypeDeclaration typeDeclaration = scope.referenceContext;
TypeReference superclassRef = typeDeclaration == null ? null : typeDeclaration.superclass;
TypeBinding superclass = superclassRef == null ? null : superclassRef.resolvedType;
if (superclass instanceof ProblemReferenceBinding) {
superclass = ((ProblemReferenceBinding) superclass).closestMatch();
}
if (superclass != null)
((SourceTypeBinding) typeBinding).superclass = (ReferenceBinding) superclass;
}
} else if (typeBinding instanceof BinaryTypeBinding) {
try {
typeBinding.superclass();
} catch (AbortCompilation e) {
// allow subsequent call to superclass() to succeed so that we don't have to catch AbortCompilation everywhere
((BinaryTypeBinding) typeBinding).tagBits &= ~TagBits.HasUnresolvedSuperclass;
this.builder.hierarchy.missingTypes.add(new String(typeBinding.superclass().sourceName()));
this.hasMissingSuperClass = true;
}
}
}
}
private void remember(IGenericType suppliedType, ReferenceBinding typeBinding) {
if (typeBinding == null) return;
if (++this.typeIndex == this.typeModels.length) {
System.arraycopy(this.typeModels, 0, this.typeModels = new IGenericType[this.typeIndex * 2], 0, this.typeIndex);
System.arraycopy(this.typeBindings, 0, this.typeBindings = new ReferenceBinding[this.typeIndex * 2], 0, this.typeIndex);
}
this.typeModels[this.typeIndex] = suppliedType;
this.typeBindings[this.typeIndex] = typeBinding;
}
private void remember(IType type, ReferenceBinding typeBinding) {
if (((CompilationUnit)type.getJavaScriptUnit()).isOpen()) {
try {
IGenericType genericType = (IGenericType)((JavaElement)type).getElementInfo();
remember(genericType, typeBinding);
} catch (JavaScriptModelException e) {
// cannot happen since element is open
return;
}
} else {
if (typeBinding == null) return;
TypeDeclaration typeDeclaration = ((ClassScope)((SourceTypeBinding)typeBinding).scope).referenceType();
// simple super class name
char[] superclassName = null;
TypeReference superclass;
if ((typeDeclaration.bits & ASTNode.IsAnonymousType) != 0) {
superclass = typeDeclaration.allocation.type;
} else {
superclass = typeDeclaration.superclass;
}
if (superclass != null) {
char[][] typeName = superclass.getTypeName();
superclassName = typeName == null ? null : typeName[typeName.length-1];
}
HierarchyType hierarchyType = new HierarchyType(
type,
typeDeclaration.name,
typeDeclaration.binding.modifiers,
superclassName);
remember(hierarchyType, typeDeclaration.binding);
}
}
private void rememberInferredType(InferredType inferredType, IType type, ReferenceBinding typeBinding) {
if (type.getJavaScriptUnit()!=null && ((CompilationUnit)type.getJavaScriptUnit()).isOpen()) {
try {
IGenericType genericType = (IGenericType)((JavaElement)type).getElementInfo();
remember(genericType, typeBinding);
} catch (JavaScriptModelException e) {
// cannot happen since element is open
return;
}
} else {
if (typeBinding == null) return;
// TypeDeclaration typeDeclaration = ((SourceTypeBinding)typeBinding).scope.referenceType();
// simple super class name
char[] superclassName = inferredType.getSuperClassName();
// TypeReference superclass;
// if ((typeDeclaration.bits & ASTNode.IsAnonymousType) != 0) {
// superclass = typeDeclaration.allocation.type;
// } else {
// superclass = typeDeclaration.superclass;
// }
// if (superclass != null) {
// char[][] typeName = superclass.getTypeName();
// superclassName = typeName == null ? null : typeName[typeName.length-1];
// }
HierarchyType hierarchyType = new HierarchyType(
type,
inferredType.getName(),
0,//typeDeclaration.binding.modifiers,
superclassName);
remember(hierarchyType, inferredType.binding);
}
}
/*
* Remembers all type bindings defined in the given parsed unit, adding local/anonymous types if specified.
*/
private void rememberAllTypes(CompilationUnitDeclaration parsedUnit, Object container, boolean includeLocalTypes) {
org.eclipse.wst.jsdt.core.IJavaScriptUnit cu=(container instanceof org.eclipse.wst.jsdt.core.IJavaScriptUnit)? (org.eclipse.wst.jsdt.core.IJavaScriptUnit)container:null;
org.eclipse.wst.jsdt.core.IClassFile classFile=(container instanceof org.eclipse.wst.jsdt.core.IClassFile)? (org.eclipse.wst.jsdt.core.IClassFile)container:null;
TypeDeclaration[] types = parsedUnit.types;
if (types != null) {
for (int i = 0, length = types.length; i < length; i++) {
TypeDeclaration type = types[i];
IType typeHandle= (cu!=null) ? cu.getType(new String(type.name)) : classFile.getType(new String(type.name));
rememberWithMemberTypes(type, typeHandle);
}
}
for (int i=0;i<parsedUnit.numberInferredTypes;i++) {
InferredType inferredType = parsedUnit.inferredTypes[i];
if (inferredType.isDefinition && !inferredType.isEmptyGlobal()) {
IType typeHandle = (cu != null) ? cu.getType(new String(
inferredType.getName())) : classFile
.getType(new String(inferredType.getName()));
rememberInferredType(inferredType, typeHandle,
inferredType.binding);
}
}
// if (includeLocalTypes && parsedUnit.localTypes != null) {
// HandleFactory factory = new HandleFactory();
// HashSet existingElements = new HashSet(parsedUnit.localTypeCount);
// HashMap knownScopes = new HashMap(parsedUnit.localTypeCount);
// for (int i = 0; i < parsedUnit.localTypeCount; i++) {
// LocalTypeBinding localType = parsedUnit.localTypes[i];
// ClassScope classScope = localType.scope;
// TypeDeclaration typeDecl = classScope.referenceType();
// IType typeHandle = (IType)factory.createElement(classScope, cu, existingElements, knownScopes);
// rememberWithMemberTypes(typeDecl, typeHandle);
// }
// }
}
private void rememberWithMemberTypes(TypeDeclaration typeDecl, IType typeHandle) {
remember(typeHandle, typeDecl.binding);
TypeDeclaration[] memberTypes = typeDecl.memberTypes;
if (memberTypes != null) {
for (int i = 0, length = memberTypes.length; i < length; i++) {
TypeDeclaration memberType = memberTypes[i];
rememberWithMemberTypes(memberType, typeHandle.getType(new String(memberType.name)));
}
}
}
/*
* Reports the hierarchy from the remembered bindings.
* Note that 'binaryTypeBinding' is null if focus type is a source type.
*/
private void reportHierarchy(IType focus, CompilationUnitDeclaration parsedUnit, ReferenceBinding binaryTypeBinding) {
// set focus type binding
if (focus != null) {
if (binaryTypeBinding != null) {
// binary type
this.focusType = binaryTypeBinding;
} else {
// source type
Member declaringMember = ((Member)focus).getOuterMostLocalContext();
if (declaringMember == null) {
// top level or member type
char[] fullyQualifiedName = focus.getElementName().toCharArray();
setFocusType(CharOperation.splitOn('.', fullyQualifiedName));
} else {
// anonymous or local type
if (parsedUnit != null) {
ASTNodeFinder nodeFinder = new ASTNodeFinder(parsedUnit);
InferredType inferredType=nodeFinder.findInferredType(focus);
if (inferredType!=null)
this.focusType=inferredType.binding;
else
{
TypeDeclaration typeDecl = nodeFinder.findType(focus);
if (typeDecl != null) {
this.focusType = typeDecl.binding;
}
}
}
}
}
}
// be resilient and fix super type bindings
fixSupertypeBindings();
int objectIndex = -1;
for (int current = this.typeIndex; current >= 0; current--) {
ReferenceBinding typeBinding = this.typeBindings[current];
// java.lang.Object treated at the end
if (typeBinding.id == TypeIds.T_JavaLangObject) {
objectIndex = current;
continue;
}
IGenericType suppliedType = this.typeModels[current];
if (!subOrSuperOfFocus(typeBinding)) {
continue; // ignore types outside of hierarchy
}
IType superclass = findSuperClass(suppliedType, typeBinding);
this.builder.connect(suppliedType, this.builder.getHandle(suppliedType, typeBinding), superclass);
}
// add java.lang.Object only if the super class is not missing
if (!this.hasMissingSuperClass && objectIndex > -1) {
IGenericType objectType = this.typeModels[objectIndex];
this.builder.connect(objectType, this.builder.getHandle(objectType, this.typeBindings[objectIndex]), null);
}
}
private void reset(){
this.lookupEnvironment.reset();
this.focusType = null;
this.superTypesOnly = false;
this.typeIndex = -1;
this.typeModels = new IGenericType[5];
this.typeBindings = new ReferenceBinding[5];
if(parsedUnits != null)
this.parsedUnits.clear();
}
/**
* Resolve the supertypes for the supplied source type.
* Inform the requestor of the resolved supertypes using:
* connect(ISourceType suppliedType, IGenericType superclass)
* @param suppliedType
*/
public void resolve(IGenericType suppliedType) {
try {
if (suppliedType.isBinaryType()) {
ReferenceBinding binaryTypeBinding = this.lookupEnvironment.cacheBinaryType((ISourceType) suppliedType, false/*don't need field and method (bug 125067)*/, null /*no access restriction*/);
remember(suppliedType, binaryTypeBinding);
// We still need to add superclasses binding (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=53095)
int startIndex = this.typeIndex;
for (int i = startIndex; i <= this.typeIndex; i++) {
IGenericType igType = this.typeModels[i];
if (igType != null && igType.isBinaryType()) {
// fault in its hierarchy...
try {
ReferenceBinding typeBinding = this.typeBindings[i];
typeBinding.superclass();
} catch (AbortCompilation e) {
// classpath problem for this type: ignore
}
}
}
this.superTypesOnly = true;
reportHierarchy(this.builder.getType(), null, binaryTypeBinding);
} else {
org.eclipse.wst.jsdt.core.IJavaScriptUnit cu = ((SourceTypeElementInfo)suppliedType).getHandle().getJavaScriptUnit();
HashSet localTypes = new HashSet();
localTypes.add(cu.getPath().toString());
this.superTypesOnly = true;
resolve(new Openable[] {(Openable)cu}, localTypes, null);
}
} 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 types contained in the given openables (ICompilationUnits and/or IClassFiles).
* Inform the requestor of the resolved supertypes for each
* supplied source type using:
* connect(ISourceType suppliedType, IGenericType superclass)
*
* Also inform the requestor of the supertypes of each
* additional requested super type which is also a source type
* instead of a binary type.
* @param openables
* @param localTypes
* @param monitor
*/
public void resolve(Openable[] openables, HashSet localTypes, IProgressMonitor monitor) {
try {
int openablesLength = openables.length;
CompilationUnitDeclaration[] parsedUnits = new CompilationUnitDeclaration[openablesLength];
boolean[] hasLocalType = new boolean[openablesLength];
org.eclipse.wst.jsdt.core.IJavaScriptUnit[] cus = new org.eclipse.wst.jsdt.core.IJavaScriptUnit[openablesLength];
int unitsIndex = 0;
CompilationUnitDeclaration focusUnit = null;
ReferenceBinding focusBinaryBinding = null;
IType focus = this.builder.getType();
Openable focusOpenable = null;
if (focus != null) {
if (focus.isBinary()) {
focusOpenable = (Openable)focus.getClassFile();
} else {
focusOpenable = (Openable)focus.getJavaScriptUnit();
}
}
processedUnits=new HashSet();
// build type bindings
Parser parser = new Parser(this.lookupEnvironment.problemReporter, true);
for (int i = 0; i < openablesLength; i++) {
Openable openable = openables[i];
if (openable instanceof org.eclipse.wst.jsdt.core.IJavaScriptUnit) {
org.eclipse.wst.jsdt.core.IJavaScriptUnit cu = (org.eclipse.wst.jsdt.core.IJavaScriptUnit)openable;
// contains a potential subtype as a local or anonymous type?
boolean containsLocalType = false;
if (localTypes == null) { // case of hierarchy on region
containsLocalType = true;
} else {
IPath path = cu.getPath();
containsLocalType = localTypes.contains(path.toString());
}
// build parsed unit
CompilationUnitDeclaration parsedUnit = null;
if (cu.isOpen()) {
// create parsed unit from source element infos
CompilationResult result = new CompilationResult(((ICompilationUnit)cu).getFileName(), ((ICompilationUnit)cu).getPackageName(), i, openablesLength, this.options.maxProblemsPerUnit);
SourceTypeElementInfo[] typeInfos = null;
try {
IType[] topLevelTypes = cu.getTypes();
int topLevelLength = topLevelTypes.length;
if (topLevelLength == 0) continue; // empty cu: no need to parse (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=65677)
typeInfos = new SourceTypeElementInfo[topLevelLength];
for (int j = 0; j < topLevelLength; j++) {
IType topLevelType = topLevelTypes[j];
typeInfos[j] = (SourceTypeElementInfo)((JavaElement)topLevelType).getElementInfo();
}
} catch (JavaScriptModelException e) {
// types/cu exist since cu is opened
}
int flags = !containsLocalType
? SourceTypeConverter.MEMBER_TYPE
: SourceTypeConverter.FIELD_AND_METHOD | SourceTypeConverter.MEMBER_TYPE | SourceTypeConverter.LOCAL_TYPE;
parsedUnit =
SourceTypeConverter.buildCompilationUnit(
typeInfos,
flags,
this.lookupEnvironment.problemReporter,
result);
if (containsLocalType) parsedUnit.bits |= ASTNode.HasAllMethodBodies;
} else {
// create parsed unit from file
IFile file = (IFile) cu.getResource();
ICompilationUnit sourceUnit = this.builder.createCompilationUnitFromPath(openable, file);
CompilationResult unitResult = new CompilationResult(sourceUnit, i, openablesLength, this.options.maxProblemsPerUnit);
parsedUnit = parser.dietParse(sourceUnit, unitResult);
}
if (parsedUnit != null) {
parser.inferTypes(parsedUnit, this.options);
hasLocalType[unitsIndex] = containsLocalType;
cus[unitsIndex] = cu;
parsedUnits[unitsIndex++] = parsedUnit;
try {
if (!processedUnits.contains(openable))
this.lookupEnvironment.buildTypeBindings(parsedUnit, null /*no access restriction*/);
processedUnits.add(openable);
if (openable.equals(focusOpenable)) {
focusUnit = parsedUnit;
}
} catch (AbortCompilation e) {
// classpath problem for this type: ignore
}
}
} else {
// cache binary type binding
ClassFile classFile = (ClassFile)openable;
org.eclipse.wst.jsdt.internal.compiler.batch.CompilationUnit sourceUnit =
new org.eclipse.wst.jsdt.internal.compiler.batch.CompilationUnit(null,new String(classFile.getFileName()),this.options.defaultEncoding);
//sourceUnit.packageName=Util.toCharArrays(new String[]{classFile.getParent().getElementName()});
CompilationResult unitResult = new CompilationResult(sourceUnit, i, openablesLength, this.options.maxProblemsPerUnit);
CompilationUnitDeclaration parsedUnit = parser.dietParse(sourceUnit, unitResult);
if (parsedUnit != null) {
parser.inferTypes(parsedUnit, this.options);
hasLocalType[unitsIndex] = true;
cus[unitsIndex] = null;
parsedUnits[unitsIndex++] = parsedUnit;
try {
this.lookupEnvironment.buildTypeBindings(parsedUnit, null /*no access restriction*/);
if (openable.equals(focusOpenable)) {
focusUnit = parsedUnit;
}
} catch (AbortCompilation e) {
// classpath problem for this type: ignore
}
}
// ISourceType binaryType = null;
// if (classFile.isOpen()) {
// // create binary type from info
// IType type = classFile.getType();
// try {
// binaryType = (ISourceType)((JavaElement)type).getElementInfo();
// } catch (JavaScriptModelException e) {
// // type exists since class file is opened
// }
// } else {
// // create binary type from file
// if (classFile.getPackageFragmentRoot().isArchive()) {
// binaryType = this.builder.createInfoFromClassFileInJar(classFile);
// } else {
// IResource file = classFile.getResource();
// binaryType = this.builder.createInfoFromClassFile(classFile, file);
// }
// }
// if (binaryType != null) {
// try {
// BinaryTypeBinding binaryTypeBinding = this.lookupEnvironment.cacheBinaryType(binaryType, false/*don't need field and method (bug 125067)*/, null /*no access restriction*/);
// remember(binaryType, binaryTypeBinding);
// if (openable.equals(focusOpenable)) {
// focusBinaryBinding = binaryTypeBinding;
// }
// } catch (AbortCompilation e) {
// // classpath problem for this type: ignore
// }
// }
}
}
for (int i = 0; i <= this.typeIndex; i++) {
IGenericType suppliedType = this.typeModels[i];
if (suppliedType != null && suppliedType.isBinaryType()) {
// fault in its hierarchy...
try {
ReferenceBinding typeBinding = this.typeBindings[i];
typeBinding.superclass();
} catch (AbortCompilation e) {
// classpath problem for this type: ignore
}
}
}
// complete type bindings (ie. connect super types)
for (int i = 0; i < unitsIndex; i++) {
CompilationUnitDeclaration parsedUnit = parsedUnits[i];
if (parsedUnit != null) {
try {
boolean containsLocalType = hasLocalType[i];
if (containsLocalType) { // NB: no-op if method bodies have been already parsed
parser.getMethodBodies(parsedUnit);
}
// complete type bindings and build fields and methods only for local types
// (in this case the constructor is needed when resolving local types)
// (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=145333)
this.lookupEnvironment.completeTypeBindings(parsedUnit, containsLocalType);
} catch (AbortCompilation e) {
// classpath problem for this type: don't try to resolve (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=49809)
hasLocalType[i] = false;
}
}
worked(monitor, 1);
}
// remember type bindings
for (int i = 0; i < unitsIndex; i++) {
CompilationUnitDeclaration parsedUnit = parsedUnits[i];
if (parsedUnit != null) {
boolean containsLocalType = hasLocalType[i];
if (containsLocalType) {
parsedUnit.scope.faultInTypes();
parsedUnit.resolve();
}
rememberAllTypes(parsedUnit, openables[i], containsLocalType);
}
}
// if no potential subtype was a real subtype of the binary focus type, no need to go further
// (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=54043)
if (focus != null && focus.isBinary()) {
char [] typeName=focus.getElementName().toCharArray();
char [] pkgName=focus.getPackageFragment().getElementName().toCharArray();
char [][]qualifiedName=new char[][]{pkgName,typeName};
focusBinaryBinding = this.lookupEnvironment.getCachedType(qualifiedName);
if (focusBinaryBinding == null) {
qualifiedName=new char[][]{typeName};
focusBinaryBinding = this.lookupEnvironment.getCachedType(qualifiedName);
}
if (focusBinaryBinding == null)
return;
}
reportHierarchy(focus, focusUnit, focusBinaryBinding);
} 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
if (TypeHierarchy.DEBUG)
e.printStackTrace();
} finally {
reset();
}
}
private void setEnvironment(LookupEnvironment lookupEnvironment, HierarchyBuilder builder) {
this.lookupEnvironment = lookupEnvironment;
this.builder = builder;
this.typeIndex = -1;
this.typeModels = new IGenericType[5];
this.typeBindings = new ReferenceBinding[5];
}
/*
* 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.getCachedType(compoundName);
if (this.focusType == null) {
this.focusType = this.lookupEnvironment.askForType(compoundName);
}
if (this.focusType==null)
{
char [][] singleName= {CharOperation.concatWith(compoundName, '.')};
this.focusType = this.lookupEnvironment.getCachedType(singleName);
if (this.focusType == null) {
this.focusType = this.lookupEnvironment.askForType(singleName);
}
}
return this.focusType;
}
public boolean subOrSuperOfFocus(ReferenceBinding typeBinding) {
if (this.focusType == null) return true; // accept all types (case of hierarchy in a region)
try {
if (this.subTypeOfType(this.focusType, typeBinding)) return true;
if (!this.superTypesOnly && this.subTypeOfType(typeBinding, this.focusType)) return true;
} catch (AbortCompilation e) {
// unresolved superclass -> ignore
}
return false;
}
private boolean subTypeOfType(ReferenceBinding subType, ReferenceBinding typeBinding) {
if (typeBinding == null || subType == null) return false;
if (subType == typeBinding) return true;
ReferenceBinding superclass = subType.superclass();
if (superclass != null && superclass.id == TypeIds.T_JavaLangObject && subType.isHierarchyInconsistent()) return false;
if (this.subTypeOfType(superclass, typeBinding)) return true;
return false;
}
protected void worked(IProgressMonitor monitor, int work) {
if (monitor != null) {
if (monitor.isCanceled()) {
throw new OperationCanceledException();
} else {
monitor.worked(work);
}
}
}
public CompilationUnitDeclaration doParse(ICompilationUnit sourceUnit, AccessRestriction accessRestriction) {
Parser parser = new Parser(this.lookupEnvironment.problemReporter, true);
CompilationResult unitResult =
new CompilationResult(sourceUnit, 1, 1, this.options.maxProblemsPerUnit);
CompilationUnitDeclaration declaration = parser.dietParse(sourceUnit, unitResult);
parser.inferTypes(declaration,this.options);
return declaration;
}
}