Copyright (c) 2000, 2018 IBM Corporation and others. This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 which accompanies this distribution, and is available at https://www.eclipse.org/legal/epl-2.0/ SPDX-License-Identifier: EPL-2.0 Contributors: IBM Corporation - initial API and implementation Stephan Herrmann - contribution for Bug 300576 - NPE Computing type hierarchy when compliance doesn't match libraries
/******************************************************************************* * Copyright (c) 2000, 2018 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * IBM Corporation - initial API and implementation * Stephan Herrmann - contribution for Bug 300576 - NPE Computing type hierarchy when compliance doesn't match libraries *******************************************************************************/
package org.eclipse.jdt.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.HashMap; import java.util.HashSet; import java.util.Map; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.SubMonitor; import org.eclipse.jdt.core.IModuleDescription; import org.eclipse.jdt.core.IPackageFragmentRoot; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.Signature; import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.internal.compiler.CompilationResult; import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies; import org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy; import org.eclipse.jdt.internal.compiler.IProblemFactory; import org.eclipse.jdt.internal.compiler.ast.*; import org.eclipse.jdt.internal.compiler.ast.LambdaExpression; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.env.AccessRestriction; import org.eclipse.jdt.internal.compiler.env.IBinaryType; import org.eclipse.jdt.internal.compiler.env.ICompilationUnit; import org.eclipse.jdt.internal.compiler.env.IGenericType; import org.eclipse.jdt.internal.compiler.env.INameEnvironment; import org.eclipse.jdt.internal.compiler.env.ISourceType; import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; import org.eclipse.jdt.internal.compiler.impl.ITypeRequestor; import org.eclipse.jdt.internal.compiler.lookup.*; import org.eclipse.jdt.internal.compiler.parser.Parser; import org.eclipse.jdt.internal.compiler.parser.SourceTypeConverter; import org.eclipse.jdt.internal.compiler.problem.AbortCompilation; import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory; import org.eclipse.jdt.internal.compiler.problem.ProblemReporter; import org.eclipse.jdt.internal.compiler.util.Messages; import org.eclipse.jdt.internal.core.*; import org.eclipse.jdt.internal.core.util.ASTNodeFinder; import org.eclipse.jdt.internal.core.util.HandleFactory; @SuppressWarnings({"rawtypes", "unchecked"}) public class HierarchyResolver implements ITypeRequestor { private ReferenceBinding focusType; private boolean superTypesOnly; private boolean hasMissingSuperClass; LookupEnvironment lookupEnvironment; private CompilerOptions options; HierarchyBuilder builder; private ReferenceBinding[] typeBindings; private BindingMap<IGenericType> bindingMap = new BindingMap<>(); private int typeIndex; private IGenericType[] typeModels; private Parser basicParser; private static final CompilationUnitDeclaration FakeUnit; static { IErrorHandlingPolicy policy = DefaultErrorHandlingPolicies.exitAfterAllProblems(); ProblemReporter problemReporter = new ProblemReporter(policy, new CompilerOptions(), new DefaultProblemFactory()); CompilationResult result = new CompilationResult(CharOperation.NO_CHAR, 0, 0, 0); FakeUnit = new CompilationUnitDeclaration(problemReporter, result, 0); } 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); LookupEnvironment environment = new LookupEnvironment(this, this.options, problemReporter, nameEnvironment); environment.mayTolerateMissingType = true; setEnvironment(environment, builder); } public HierarchyResolver(LookupEnvironment lookupEnvironment, HierarchyBuilder builder) { setEnvironment(lookupEnvironment, builder); }
Add an additional binary type
Params:
  • binaryType –
  • packageBinding –
/** * Add an additional binary type * @param binaryType * @param packageBinding */
@Override public void accept(IBinaryType binaryType, PackageBinding packageBinding, AccessRestriction accessRestriction) { IProgressMonitor progressMonitor = this.builder.hierarchy.progressMonitor; if (progressMonitor != null && progressMonitor.isCanceled()) throw new OperationCanceledException(); sanitizeBinaryType(binaryType); BinaryTypeBinding typeBinding = this.lookupEnvironment.createBinaryTypeFrom(binaryType, packageBinding, accessRestriction); try { this.remember(binaryType, typeBinding); } catch (AbortCompilation e) { // ignore } } private void sanitizeBinaryType(IGenericType binaryType) { if (binaryType instanceof HierarchyBinaryType) { HierarchyBinaryType hierarchyBinaryType = (HierarchyBinaryType) binaryType; if (hierarchyBinaryType.getSuperclassName() == null) hierarchyBinaryType.recordSuperclass(CharOperation.concatWith(TypeConstants.JAVA_LANG_OBJECT, '/')); } }
Add an additional compilation unit.
Params:
  • sourceUnit –
/** * Add an additional compilation unit. * @param sourceUnit */
@Override public void accept(ICompilationUnit sourceUnit, AccessRestriction accessRestriction) { if (CharOperation.equals(TypeConstants.MODULE_INFO_NAME, sourceUnit.getMainTypeName())) { // module is needed for resolving, so parse and build it now: CompilationResult unitResult = new CompilationResult(sourceUnit, 1, 1, this.options.maxProblemsPerUnit); CompilationUnitDeclaration parsedUnit = basicParser().dietParse(sourceUnit, unitResult); this.lookupEnvironment.buildTypeBindings(parsedUnit, accessRestriction); this.lookupEnvironment.completeTypeBindings(parsedUnit, true); // work done inside checkAndSetImports() } else { //System.out.println("Cannot accept compilation units inside the HierarchyResolver."); this.lookupEnvironment.problemReporter.abortDueToInternalError( new StringBuffer(Messages.accept_cannot) .append(sourceUnit.getFileName()) .toString()); } } private Parser basicParser() { if (this.basicParser == null) { ProblemReporter problemReporter = new ProblemReporter( DefaultErrorHandlingPolicies.proceedWithAllProblems(), this.options, new DefaultProblemFactory()); this.basicParser = new Parser(problemReporter, false); this.basicParser.reportOnlyOneSyntaxError = true; } return this.basicParser; }
Add additional source types
Params:
  • sourceTypes –
  • packageBinding –
/** * Add additional source types * @param sourceTypes * @param packageBinding */
@Override public void accept(ISourceType[] sourceTypes, PackageBinding packageBinding, AccessRestriction accessRestriction) { IProgressMonitor progressMonitor = this.builder.hierarchy.progressMonitor; if (progressMonitor != null && progressMonitor.isCanceled()) throw new OperationCanceledException(); // find most enclosing type first (needed when explicit askForType(...) is done // with a member type (e.g. p.A$B)) ISourceType sourceType = sourceTypes[0]; while (sourceType.getEnclosingType() != null) sourceType = sourceType.getEnclosingType(); // build corresponding compilation unit CompilationResult result = new CompilationResult(sourceType.getFileName(), 1, 1, this.options.maxProblemsPerUnit); CompilationUnitDeclaration unit = SourceTypeConverter.buildCompilationUnit( new ISourceType[] {sourceType}, // ignore secondary types, to improve laziness SourceTypeConverter.MEMBER_TYPE | (this.lookupEnvironment.globalOptions.sourceLevel >= ClassFileConstants.JDK1_8 ? SourceTypeConverter.METHOD : 0), // need member types // no need for field initialization this.lookupEnvironment.problemReporter, result); // build bindings if (unit != null) { try { LookupEnvironment environment = packageBinding.environment; if (environment == null) environment = this.lookupEnvironment; environment.buildTypeBindings(unit, accessRestriction); org.eclipse.jdt.core.ICompilationUnit cu = ((SourceTypeElementInfo)sourceType).getHandle().getCompilationUnit(); rememberAllTypes(unit, cu, false); environment.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) { superBinding = (ReferenceBinding) superBinding.erasure(); 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; } } } } IGenericType typeModel = this.bindingMap.get(superBinding); if (typeModel != null) { return this.builder.getHandle(typeModel, superBinding); } } return null; } /* * Returns the handles of the super interfaces of the given type. * Adds the simple name to the hierarchy missing types if an interface is not found (but don't put null in the returned array) */ private IType[] findSuperInterfaces(IGenericType type, ReferenceBinding typeBinding) { char[][] superInterfaceNames; char separator; if (type instanceof IBinaryType) { superInterfaceNames = ((IBinaryType)type).getInterfaceNames(); separator = '/'; } else if (type instanceof ISourceType) { ISourceType sourceType = (ISourceType)type; if (sourceType.isAnonymous()) { // if anonymous type if (typeBinding.superInterfaces() != null && typeBinding.superInterfaces().length > 0) { superInterfaceNames = new char[][] {sourceType.getSuperclassName()}; } else { superInterfaceNames = sourceType.getInterfaceNames(); } } else { if (TypeDeclaration.kind(sourceType.getModifiers()) == TypeDeclaration.ANNOTATION_TYPE_DECL) superInterfaceNames = new char[][] {TypeConstants.CharArray_JAVA_LANG_ANNOTATION_ANNOTATION}; else superInterfaceNames = sourceType.getInterfaceNames(); } separator = '.'; } else if (type instanceof HierarchyType) { HierarchyType hierarchyType = (HierarchyType)type; if (hierarchyType.isAnonymous()) { // if anonymous type if (typeBinding.superInterfaces() != null && typeBinding.superInterfaces().length > 0) { superInterfaceNames = new char[][] {hierarchyType.superclassName}; } else { superInterfaceNames = hierarchyType.superInterfaceNames; } } else { superInterfaceNames = hierarchyType.superInterfaceNames; } separator = '.'; } else{ return null; } ReferenceBinding[] interfaceBindings = typeBinding.superInterfaces(); int bindingIndex = 0; int bindingLength = interfaceBindings == null ? 0 : interfaceBindings.length; int length = superInterfaceNames == null ? 0 : superInterfaceNames.length; IType[] superinterfaces = new IType[length]; int index = 0; next : for (int i = 0; i < length; i++) { char[] superInterfaceName = superInterfaceNames[i]; int end = superInterfaceName.length; // find the end of simple name int genericStart = CharOperation.indexOf(Signature.C_GENERIC_START, superInterfaceName); if (genericStart != -1) end = genericStart; // find the start of simple name int lastSeparator = CharOperation.lastIndexOf(separator, superInterfaceName, 0, end); int start = lastSeparator + 1; // case of binary inner type -> take the last part int lastDollar = CharOperation.lastIndexOf('$', superInterfaceName, start); if (lastDollar != -1) start = lastDollar + 1; char[] simpleName = CharOperation.subarray(superInterfaceName, start, end); if (bindingIndex < bindingLength) { ReferenceBinding interfaceBinding = (ReferenceBinding) interfaceBindings[bindingIndex].erasure(); // ensure that the binding corresponds to the interface defined by the user if (CharOperation.equals(simpleName, interfaceBinding.sourceName)) { bindingIndex++; IGenericType genericType = this.bindingMap.get(interfaceBinding); if (genericType != null) { IType handle = this.builder.getHandle(genericType, interfaceBinding); if (handle != null) { superinterfaces[index++] = handle; continue next; } } } } this.builder.hierarchy.missingTypes.add(new String(simpleName)); } if (index != length) System.arraycopy(superinterfaces, 0, superinterfaces = new IType[index], 0, index); return superinterfaces; } /* * For all type bindings that have hierarchy problems, artificially fix their superclass/superInterfaces so that the connection * can be made. */ private void fixSupertypeBindings() { for (int current = this.typeIndex; current >= 0; current--) { ReferenceBinding typeBinding = this.typeBindings[current]; if ((typeBinding.tagBits & TagBits.HierarchyHasProblems) == 0) continue; if (typeBinding instanceof SourceTypeBinding) { if (typeBinding instanceof LocalTypeBinding) { LocalTypeBinding localTypeBinding = (LocalTypeBinding) typeBinding; QualifiedAllocationExpression allocationExpression = localTypeBinding.scope.referenceContext.allocation; TypeReference type; if (allocationExpression != null && (type = allocationExpression.type) != null && type.resolvedType != null) { localTypeBinding.setSuperClass((ReferenceBinding) type.resolvedType); continue; } } ClassScope scope = ((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 != null) { superclass = superclass.closestMatch(); } if (superclass instanceof ReferenceBinding) { // ensure we are not creating a cycle (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=215681 ) if (!(subTypeOfType((ReferenceBinding) superclass, typeBinding))) { ((SourceTypeBinding) typeBinding).setSuperClass((ReferenceBinding) superclass); } } TypeReference[] superInterfaces = typeDeclaration == null ? null : typeDeclaration.superInterfaces; int length; ReferenceBinding[] interfaceBindings = typeBinding.superInterfaces(); if (superInterfaces != null && (length = superInterfaces.length) > (interfaceBindings == null ? 0 : interfaceBindings.length)) { // check for interfaceBindings being null (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=139689) interfaceBindings = new ReferenceBinding[length]; int index = 0; for (int i = 0; i < length; i++) { TypeBinding superInterface = superInterfaces[i].resolvedType; if (superInterface != null) { superInterface = superInterface.closestMatch(); } if (superInterface instanceof ReferenceBinding) { // ensure we are not creating a cycle (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=215681 ) if (!(subTypeOfType((ReferenceBinding) superInterface, typeBinding))) { interfaceBindings[index++] = (ReferenceBinding) superInterface; } } } if (index < length) System.arraycopy(interfaceBindings, 0, interfaceBindings = new ReferenceBinding[index], 0 , index); ((SourceTypeBinding) typeBinding).setSuperInterfaces(interfaceBindings); } } } 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; } try { typeBinding.superInterfaces(); } catch (AbortCompilation e) { // allow subsequent call to superInterfaces() to succeed so that we don't have to catch AbortCompilation everywhere ((BinaryTypeBinding) typeBinding).tagBits &= ~TagBits.HasUnresolvedSuperinterfaces; } } } } 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; this.bindingMap.put(typeBinding, suppliedType); } private void remember(IType type, ReferenceBinding typeBinding) { if (((CompilationUnit)type.getCompilationUnit()).isOpen()) { try { IGenericType genericType = (IGenericType)((JavaElement)type).getElementInfo(); remember(genericType, typeBinding); } catch (JavaModelException e) { // cannot happen since element is open return; } } else { if (typeBinding == null) return; boolean isAnonymous = false; try { isAnonymous = type.isAnonymous(); } catch(JavaModelException jme) { // Ignore } if (typeBinding instanceof SourceTypeBinding) { TypeDeclaration typeDeclaration = ((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]; } // simple super interface names char[][] superInterfaceNames = null; TypeReference[] superInterfaces = typeDeclaration.superInterfaces; if (superInterfaces != null) { int length = superInterfaces.length; superInterfaceNames = new char[length][]; for (int i = 0; i < length; i++) { TypeReference superInterface = superInterfaces[i]; char[][] typeName = superInterface.getTypeName(); superInterfaceNames[i] = typeName[typeName.length-1]; } } HierarchyType hierarchyType = new HierarchyType( type, typeDeclaration.name, typeDeclaration.binding.modifiers, superclassName, superInterfaceNames, isAnonymous); remember(hierarchyType, typeDeclaration.binding); } else { HierarchyType hierarchyType = new HierarchyType( type, typeBinding.sourceName(), typeBinding.modifiers, typeBinding.superclass().sourceName(), new char [][] { typeBinding.superInterfaces()[0].sourceName() }, isAnonymous); remember(hierarchyType, typeBinding); } } } /* * Remembers all type bindings defined in the given parsed unit, adding local/anonymous types if specified. */ private void rememberAllTypes(CompilationUnitDeclaration parsedUnit, org.eclipse.jdt.core.ICompilationUnit cu, boolean includeLocalTypes) { TypeDeclaration[] types = parsedUnit.types; if (types != null) { for (int i = 0, length = types.length; i < length; i++) { TypeDeclaration type = types[i]; rememberWithMemberTypes(type, cu.getType(new String(type.name))); } } if (!includeLocalTypes || (parsedUnit.localTypes == null && parsedUnit.functionalExpressions == null)) return; HandleFactory factory = new HandleFactory(); HashSet existingElements = new HashSet(parsedUnit.localTypeCount + parsedUnit.functionalExpressionsCount); HashMap knownScopes = new HashMap(parsedUnit.localTypeCount + parsedUnit.functionalExpressionsCount); if (parsedUnit.localTypes != null) { 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); } } if (parsedUnit.functionalExpressions != null) { for (int i = 0; i < parsedUnit.functionalExpressionsCount; i++) { if (parsedUnit.functionalExpressions[i] instanceof LambdaExpression) { final LambdaExpression expression = (LambdaExpression) parsedUnit.functionalExpressions[i]; if (expression.resolvedType != null && expression.resolvedType.isValidBinding()) { IType typeHandle = (IType)factory.createLambdaTypeElement(expression, cu, existingElements, knownScopes); remember(typeHandle, expression.getTypeBinding()); } } } } } 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, TypeDeclaration focusLocalType, ReferenceBinding binaryTypeBinding) { // set focus type binding if (focus != null) { if (binaryTypeBinding != null) { // binary type this.focusType = binaryTypeBinding; } else { // source type if (focusLocalType != null) { // anonymous or local type this.focusType = focusLocalType.binding; } else { // top level or member type char[] fullyQualifiedName = focus.getFullyQualifiedName().toCharArray(); setFocusType(CharOperation.splitOn('.', fullyQualifiedName)); } } } // be resilient and fix super type bindings fixSupertypeBindings(); int objectIndex = -1; IProgressMonitor progressMonitor = this.builder.hierarchy.progressMonitor; for (int current = this.typeIndex; current >= 0; current--) { if (progressMonitor != null && progressMonitor.isCanceled()) throw new OperationCanceledException(); 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; if (typeBinding.isInterface()){ // do not connect interfaces to Object superclass = null; } else { superclass = findSuperClass(suppliedType, typeBinding); } IType[] superinterfaces = findSuperInterfaces(suppliedType, typeBinding); this.builder.connect(suppliedType, this.builder.getHandle(suppliedType, typeBinding), superclass, superinterfaces); } // add java.lang.Object only if the super class is not missing if (objectIndex > -1 && (!this.hasMissingSuperClass || this.focusType == null)) { IGenericType objectType = this.typeModels[objectIndex]; this.builder.connect(objectType, this.builder.getHandle(objectType, this.typeBindings[objectIndex]), null, 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]; this.bindingMap.clear(); }
Resolve the supertypes for the supplied source type. Inform the requestor of the resolved supertypes using: connect(ISourceType suppliedType, IGenericType superclass, IGenericType[] superinterfaces)
Params:
  • suppliedType –
/** * Resolve the supertypes for the supplied source type. * Inform the requestor of the resolved supertypes using: * connect(ISourceType suppliedType, IGenericType superclass, IGenericType[] superinterfaces) * @param suppliedType */
public void resolve(IGenericType suppliedType) { try { if (suppliedType.isBinaryType()) { sanitizeBinaryType(suppliedType); BinaryTypeBinding binaryTypeBinding = this.lookupEnvironment.cacheBinaryType((IBinaryType) suppliedType, false/*don't need field and method (bug 125067)*/, null /*no access restriction*/); remember(suppliedType, binaryTypeBinding); // We still need to add superclasses and superinterfaces bindings (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()) { CompilationUnitDeclaration previousUnitBeingCompleted = this.lookupEnvironment.unitBeingCompleted; // fault in its hierarchy... try { // ensure that unitBeingCompleted is set so that we don't get an AbortCompilation for a missing type // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=213249 ) if (previousUnitBeingCompleted == null) { this.lookupEnvironment.unitBeingCompleted = FakeUnit; } ReferenceBinding typeBinding = this.typeBindings[i]; typeBinding.superclass(); typeBinding.superInterfaces(); } catch (AbortCompilation e) { // classpath problem for this type: ignore } finally { this.lookupEnvironment.unitBeingCompleted = previousUnitBeingCompleted; } } } this.superTypesOnly = true; reportHierarchy(this.builder.getType(), null, binaryTypeBinding); } else { org.eclipse.jdt.core.ICompilationUnit cu = ((SourceTypeElementInfo)suppliedType).getHandle().getCompilationUnit(); if (cu != null) { 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, 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.
Params:
  • openables –
  • localTypes –
  • monitor –
/** * 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, 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. * @param openables * @param localTypes * @param monitor */
public void resolve(Openable[] openables, HashSet localTypes, IProgressMonitor monitor) { SubMonitor subMonitor = SubMonitor.convert(monitor, 3); try { int openablesLength = openables.length; CompilationUnitDeclaration[] parsedUnits = new CompilationUnitDeclaration[openablesLength]; boolean[] hasLocalType = new boolean[openablesLength]; org.eclipse.jdt.core.ICompilationUnit[] cus = new org.eclipse.jdt.core.ICompilationUnit[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.getCompilationUnit(); } } subMonitor.split(1); // build type bindings Parser parser = new Parser(this.lookupEnvironment.problemReporter, true); final boolean isJava8 = this.options.sourceLevel >= ClassFileConstants.JDK1_8; for (int i = 0; i < openablesLength; i++) { Openable openable = openables[i]; if (openable instanceof org.eclipse.jdt.core.ICompilationUnit) { org.eclipse.jdt.core.ICompilationUnit cu = (org.eclipse.jdt.core.ICompilationUnit)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 = cu.isWorkingCopy() ? true /* presume conservatively */ : 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, 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 (JavaModelException e) { // types/cu exist since cu is opened } int flags = !containsLocalType ? SourceTypeConverter.MEMBER_TYPE | (isJava8 ? SourceTypeConverter.METHOD : 0) : SourceTypeConverter.FIELD_AND_METHOD | SourceTypeConverter.MEMBER_TYPE | SourceTypeConverter.LOCAL_TYPE; parsedUnit = SourceTypeConverter.buildCompilationUnit( typeInfos, flags, this.lookupEnvironment.problemReporter, result); // We would have got all the necessary local types by now and hence there is no further need // to parse the method bodies. Parser.getMethodBodies, which is called latter in this function, // will not parse the method statements if ASTNode.HasAllMethodBodies is set. if (containsLocalType && parsedUnit != null) parsedUnit.bits |= ASTNode.HasAllMethodBodies; } else { // create parsed unit from file IFile file = (IFile) cu.getResource(); ICompilationUnit sourceUnit = this.builder.createCompilationUnitFromPath(openable, file, findAssociatedModuleName(openable)); CompilationResult unitResult = new CompilationResult(sourceUnit, i, openablesLength, this.options.maxProblemsPerUnit); parsedUnit = parser.dietParse(sourceUnit, unitResult); } if (parsedUnit != null) { hasLocalType[unitsIndex] = containsLocalType; cus[unitsIndex] = cu; 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 } } } else { // cache binary type binding ClassFile classFile = (ClassFile)openable; IBinaryType binaryType = (IBinaryType) JavaModelManager.getJavaModelManager().getInfo(classFile.getType()); if (binaryType == null) { // create binary type from file if (classFile.getPackageFragmentRoot().isArchive()) { binaryType = this.builder.createInfoFromClassFileInJar(classFile); } else { IResource file = classFile.resource(); binaryType = this.builder.createInfoFromClassFile(classFile, file); } } if (binaryType != null) { try { sanitizeBinaryType(binaryType); 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 } } } } // remember type declaration of focus if local/anonymous early (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=210498) TypeDeclaration focusLocalType = null; if (focus != null && focusBinaryBinding == null && focusUnit != null && ((Member)focus).getOuterMostLocalContext() != null) { focusLocalType = new ASTNodeFinder(focusUnit).findType(focus); } for (int i = 0; i <= this.typeIndex; i++) { IGenericType suppliedType = this.typeModels[i]; if (suppliedType != null && suppliedType.isBinaryType()) { CompilationUnitDeclaration previousUnitBeingCompleted = this.lookupEnvironment.unitBeingCompleted; // fault in its hierarchy... try { // ensure that unitBeingCompleted is set so that we don't get an AbortCompilation for a missing type // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=213249 ) if (previousUnitBeingCompleted == null) { this.lookupEnvironment.unitBeingCompleted = FakeUnit; } ReferenceBinding typeBinding = this.typeBindings[i]; typeBinding.superclass(); typeBinding.superInterfaces(); } catch (AbortCompilation e) { // classpath problem for this type: ignore } finally { this.lookupEnvironment.unitBeingCompleted = previousUnitBeingCompleted; } } } SubMonitor unitLoopMonitor = subMonitor.split(1).setWorkRemaining(unitsIndex); // complete type bindings (i.e. connect super types) for (int i = 0; i < unitsIndex; i++) { unitLoopMonitor.split(1); CompilationUnitDeclaration parsedUnit = parsedUnits[i]; if (parsedUnit != null) { try { if (hasLocalType[i]) { // NB: no-op if method bodies have been already parsed parser.getMethodBodies(parsedUnit); } } 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; } } } // 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) try { SubMonitor completeLoopMonitor = subMonitor.split(1).setWorkRemaining(unitsIndex); this.lookupEnvironment.completeTypeBindings(parsedUnits, hasLocalType, unitsIndex); // remember type bindings for (int i = 0; i < unitsIndex; i++) { completeLoopMonitor.split(1); CompilationUnitDeclaration parsedUnit = parsedUnits[i]; // https://bugs.eclipse.org/bugs/show_bug.cgi?id=462158 // Certain assist features require type hierarchy even with code with compiler errors. if (parsedUnit != null) { boolean containsLocalType = hasLocalType[i]; if (containsLocalType) { parsedUnit.scope.faultInTypes(); parsedUnit.resolve(); } rememberAllTypes(parsedUnit, cus[i], containsLocalType); } } } catch (AbortCompilation e) { // skip it silently } // 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 (focusBinaryBinding == null && focus != null && focus.isBinary()) { char[] fullyQualifiedName = focus.getFullyQualifiedName().toCharArray(); focusBinaryBinding = this.lookupEnvironment.getCachedType(CharOperation.splitOn('.', fullyQualifiedName)); // https://bugs.eclipse.org/bugs/show_bug.cgi?id=436155 // When local types are requested, it's likely a type is found from cache without // the hierarchy being resolved completely, so consider that factor too if (focusBinaryBinding == null || (focusBinaryBinding.tagBits & TagBits.HasUnresolvedSuperclass) != 0) return; } reportHierarchy(focus, focusLocalType, 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 char[] findAssociatedModuleName(Openable openable) { IModuleDescription module = null; IPackageFragmentRoot root = openable.getPackageFragmentRoot(); try { if (root.getKind() == IPackageFragmentRoot.K_SOURCE) module = root.getJavaProject().getModuleDescription(); // from any root in this project else module = root.getModuleDescription(); } catch (JavaModelException jme) { // ignore, cannot associate to any module } if (module != null) return module.getElementName().toCharArray(); return null; } 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]; this.bindingMap.clear(); } /* * Set the focus type (i.e. 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, this.lookupEnvironment.UnNamedModule); if (this.focusType == null) { int length = compoundName.length; char[] typeName = compoundName[length-1]; int firstDollar = CharOperation.indexOf('$', typeName); if (firstDollar != -1) { compoundName[length-1] = CharOperation.subarray(typeName, 0, firstDollar); this.focusType = this.lookupEnvironment.askForType(compoundName, this.lookupEnvironment.UnNamedModule); if (this.focusType != null) { char[][] memberTypeNames = CharOperation.splitOn('$', typeName, firstDollar+1, typeName.length); for (int i = 0; i < memberTypeNames.length; i++) { this.focusType = this.focusType.getMemberType(memberTypeNames[i]); if (this.focusType == null) return null; } } } } } 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 (subTypeOfType(this.focusType, typeBinding)) return true; if (!this.superTypesOnly && subTypeOfType(typeBinding, this.focusType)) return true; } catch (AbortCompilation e) { // unresolved superclass/superinterface -> ignore } return false; } private boolean subTypeOfType(ReferenceBinding subType, ReferenceBinding typeBinding) { if (typeBinding == null || subType == null) return false; if (TypeBinding.equalsEquals(subType, typeBinding)) return true; ReferenceBinding superclass = subType.superclass(); if (superclass != null) superclass = (ReferenceBinding) superclass.erasure(); // if (superclass != null && superclass.id == TypeIds.T_JavaLangObject && subType.isHierarchyInconsistent()) return false; if (subTypeOfType(superclass, typeBinding)) return true; ReferenceBinding[] superInterfaces = subType.superInterfaces(); if (superInterfaces != null) { for (int i = 0, length = superInterfaces.length; i < length; i++) { ReferenceBinding superInterface = (ReferenceBinding) superInterfaces[i].erasure(); if (subTypeOfType(superInterface, 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); } } } }