private Binding findImport(char[][] compoundName, int length) { recordQualifiedReference(compoundName); Binding binding = this.environment.getTopLevelPackage(compoundName[0]); int i = 1; foundNothingOrType: if (binding != null) { PackageBinding packageBinding = (PackageBinding) binding; while (i < length) { binding = packageBinding.getTypeOrPackage(compoundName[i++]); if (binding == null || !binding.isValidBinding()) { binding = null; break foundNothingOrType; } if (!(binding instanceof PackageBinding)) break foundNothingOrType; packageBinding = (PackageBinding) binding; } return packageBinding; } ReferenceBinding type; if (binding == null) { if (compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4) return new ProblemReferenceBinding( CharOperation.subarray(compoundName, 0, i), null, ProblemReasons.NotFound); type = findType( compoundName[0], this.environment.defaultPackage, this.environment.defaultPackage); if (type == null || !type.isValidBinding()) return new ProblemReferenceBinding( CharOperation.subarray(compoundName, 0, i), null, ProblemReasons.NotFound); i = 1; // reset to look for member types inside the default package type } else { type = (ReferenceBinding) binding; } while (i < length) { type = (ReferenceBinding) this.environment.convertToRawType( type, false /*do not force conversion of enclosing types*/); // type imports are // necessarily raw for all // except last if (!type.canBeSeenBy(this.fPackage)) return new ProblemReferenceBinding( CharOperation.subarray(compoundName, 0, i), type, ProblemReasons.NotVisible); char[] name = compoundName[i++]; // does not look for inherited member types on purpose, only immediate members type = type.getMemberType(name); if (type == null) return new ProblemReferenceBinding( CharOperation.subarray(compoundName, 0, i), null, ProblemReasons.NotFound); } if (!type.canBeSeenBy(this.fPackage)) return new ProblemReferenceBinding(compoundName, type, ProblemReasons.NotVisible); return type; }
/** * 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()) { 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.aspectj.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(); } }
/* * 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; } } } } for (int t = this.typeIndex; t >= 0; t--) { if (TypeBinding.equalsEquals(this.typeBindings[t], superBinding)) { return this.builder.getHandle(this.typeModels[t], superBinding); } } } return null; }
// helper method for findSingleStaticImport() private MethodBinding findStaticMethod(ReferenceBinding currentType, char[] selector) { if (!currentType.canBeSeenBy(this)) return null; do { currentType.initializeForStaticImports(); MethodBinding[] methods = currentType.getMethods(selector); if (methods != Binding.NO_METHODS) { for (int i = methods.length; --i >= 0; ) { MethodBinding method = methods[i]; if (method.isStatic() && method.canBeSeenBy(this.fPackage)) return method; } } } while ((currentType = currentType.superclass()) != null); return null; }
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; }
private Binding findSingleStaticImport(char[][] compoundName, int mask) { Binding binding = findImport(compoundName, compoundName.length - 1); if (!binding.isValidBinding()) return binding; char[] name = compoundName[compoundName.length - 1]; if (binding instanceof PackageBinding) { Binding temp = ((PackageBinding) binding).getTypeOrPackage(name); if (temp != null && temp instanceof ReferenceBinding) // must resolve to a member type or field, not a top level type return new ProblemReferenceBinding( compoundName, (ReferenceBinding) temp, ProblemReasons.InvalidTypeForStaticImport); return binding; // cannot be a package, error is caught in sender } // look to see if its a static field first ReferenceBinding type = (ReferenceBinding) binding; FieldBinding field = (mask & Binding.FIELD) != 0 ? findField(type, name, null, true) : null; if (field != null) { if (field.problemId() == ProblemReasons.Ambiguous && ((ProblemFieldBinding) field).closestMatch.isStatic()) return field; // keep the ambiguous field instead of a possible method match if (field.isValidBinding() && field.isStatic() && field.canBeSeenBy(type, null, this)) return field; } // look to see if there is a static method with the same selector MethodBinding method = (mask & Binding.METHOD) != 0 ? findStaticMethod(type, name) : null; if (method != null) return method; type = findMemberType(name, type); if (type == null || !type.isStatic()) { if (field != null && !field.isValidBinding() && field.problemId() != ProblemReasons.NotFound) return field; return new ProblemReferenceBinding(compoundName, type, ProblemReasons.NotFound); } if (type.isValidBinding() && !type.canBeSeenBy(this.fPackage)) return new ProblemReferenceBinding(compoundName, type, ProblemReasons.NotVisible); if (type.problemId() == ProblemReasons.NotVisible) // ensure compoundName is correct return new ProblemReferenceBinding( compoundName, ((ProblemReferenceBinding) type).closestMatch, ProblemReasons.NotVisible); return type; }
private ReferenceBinding typeToRecord(TypeBinding type) { if (type == null) return null; while (type.isArrayType()) type = ((ArrayBinding) type).leafComponentType(); switch (type.kind()) { case Binding.BASE_TYPE: case Binding.TYPE_PARAMETER: case Binding.WILDCARD_TYPE: case Binding.INTERSECTION_TYPE: case Binding.INTERSECTION_TYPE18: // constituents would have been recorded. case Binding.POLY_TYPE: // not a real type, will mutate into one, hopefully soon. return null; case Binding.PARAMETERIZED_TYPE: case Binding.RAW_TYPE: type = type.erasure(); } ReferenceBinding refType = (ReferenceBinding) type; if (refType.isLocalType()) return null; return refType; }
public void storeDependencyInfo() { // add the type hierarchy of each referenced supertype // cannot do early since the hierarchy may not be fully resolved for (int i = 0; i < this.referencedSuperTypes.size; i++) { // grows as more types are added ReferenceBinding type = (ReferenceBinding) this.referencedSuperTypes.elementAt(i); if (!this.referencedTypes.containsIdentical(type)) this.referencedTypes.add(type); if (!type.isLocalType()) { ReferenceBinding enclosing = type.enclosingType(); if (enclosing != null) recordSuperTypeReference(enclosing); } ReferenceBinding superclass = type.superclass(); if (superclass != null) recordSuperTypeReference(superclass); ReferenceBinding[] interfaces = type.superInterfaces(); if (interfaces != null) for (int j = 0, length = interfaces.length; j < length; j++) recordSuperTypeReference(interfaces[j]); } for (int i = 0, l = this.referencedTypes.size; i < l; i++) { ReferenceBinding type = (ReferenceBinding) this.referencedTypes.elementAt(i); if (!type.isLocalType()) recordQualifiedReference( type.isMemberType() ? CharOperation.splitOn('.', type.readableName()) : type.compoundName); } int size = this.qualifiedReferences.size; char[][][] qualifiedRefs = new char[size][][]; for (int i = 0; i < size; i++) qualifiedRefs[i] = this.qualifiedReferences.elementAt(i); this.referenceContext.compilationResult.qualifiedReferences = qualifiedRefs; size = this.simpleNameReferences.size; char[][] simpleRefs = new char[size][]; for (int i = 0; i < size; i++) simpleRefs[i] = this.simpleNameReferences.elementAt(i); this.referenceContext.compilationResult.simpleNameReferences = simpleRefs; size = this.rootReferences.size; char[][] rootRefs = new char[size][]; for (int i = 0; i < size; i++) rootRefs[i] = this.rootReferences.elementAt(i); this.referenceContext.compilationResult.rootReferences = rootRefs; }
/** * 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) * * <p>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.aspectj.org.eclipse.jdt.core.ICompilationUnit[] cus = new org.aspectj.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(); } } // 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.aspectj.org.eclipse.jdt.core.ICompilationUnit) { org.aspectj.org.eclipse.jdt.core.ICompilationUnit cu = (org.aspectj.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.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) { 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 { 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; } } } // complete type bindings (i.e. connect super types) for (int i = 0; i < unitsIndex; i++) { CompilationUnitDeclaration parsedUnit = parsedUnits[i]; if (parsedUnit != null) { try { if (hasLocalType[i]) { // NB: no-op if method bodies have been already parsed if (monitor != null && monitor.isCanceled()) throw new OperationCanceledException(); 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 { this.lookupEnvironment.completeTypeBindings(parsedUnits, hasLocalType, unitsIndex); // remember type bindings for (int i = 0; i < unitsIndex; i++) { CompilationUnitDeclaration parsedUnit = parsedUnits[i]; if (parsedUnit != null && !parsedUnit.hasErrors()) { boolean containsLocalType = hasLocalType[i]; if (containsLocalType) { if (monitor != null && monitor.isCanceled()) throw new OperationCanceledException(); parsedUnit.scope.faultInTypes(); parsedUnit.resolve(); } rememberAllTypes(parsedUnit, cus[i], containsLocalType); } } } catch (AbortCompilation e) { // skip it silently } worked(monitor, 1); // 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(); } }
/* * 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 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); } } }
/* * 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; } } } }
/* * 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++; for (int t = this.typeIndex; t >= 0; t--) { if (TypeBinding.equalsEquals(this.typeBindings[t], interfaceBinding)) { IType handle = this.builder.getHandle(this.typeModels[t], 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; }
/** * Checks for duplicates. If all ok, records the importBinding returns -1 when this import is * flagged as duplicate. * * @param importBinding * @param typesBySimpleNames * @param importReference * @param compoundName * @return -1 when this import is flagged as duplicate, importPtr otherwise. */ private int checkAndRecordImportBinding( Binding importBinding, HashtableOfType typesBySimpleNames, ImportReference importReference, char[][] compoundName) { ReferenceBinding conflictingType = null; if (importBinding instanceof MethodBinding) { conflictingType = (ReferenceBinding) getType(compoundName, compoundName.length); if (!conflictingType.isValidBinding() || (importReference.isStatic() && !conflictingType.isStatic())) conflictingType = null; } // collisions between an imported static field & a type should be checked according to spec... // but currently not by javac final char[] name = compoundName[compoundName.length - 1]; if (importBinding instanceof ReferenceBinding || conflictingType != null) { ReferenceBinding referenceBinding = conflictingType == null ? (ReferenceBinding) importBinding : conflictingType; ReferenceBinding typeToCheck = referenceBinding.problemId() == ProblemReasons.Ambiguous ? ((ProblemReferenceBinding) referenceBinding).closestMatch : referenceBinding; if (importReference.isTypeUseDeprecated(typeToCheck, this)) problemReporter().deprecatedType(typeToCheck, importReference); ReferenceBinding existingType = typesBySimpleNames.get(name); if (existingType != null) { // duplicate test above should have caught this case, but make sure if (TypeBinding.equalsEquals(existingType, referenceBinding)) { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=302865 // Check all resolved imports to see if this import qualifies as a duplicate for (int j = 0; j < this.importPtr; j++) { ImportBinding resolved = this.tempImports[j]; if (resolved instanceof ImportConflictBinding) { ImportConflictBinding importConflictBinding = (ImportConflictBinding) resolved; if (TypeBinding.equalsEquals( importConflictBinding.conflictingTypeBinding, referenceBinding)) { if (!importReference.isStatic()) { // resolved is implicitly static problemReporter().duplicateImport(importReference); recordImportBinding( new ImportBinding(compoundName, false, importBinding, importReference)); } } } else if (resolved.resolvedImport == referenceBinding) { if (importReference.isStatic() != resolved.isStatic()) { problemReporter().duplicateImport(importReference); recordImportBinding( new ImportBinding(compoundName, false, importBinding, importReference)); } } } return -1; } // either the type collides with a top level type or another imported type for (int j = 0, length = this.topLevelTypes.length; j < length; j++) { if (CharOperation.equals(this.topLevelTypes[j].sourceName, existingType.sourceName)) { problemReporter().conflictingImport(importReference); return -1; } } if (importReference.isStatic() && importBinding instanceof ReferenceBinding && compilerOptions().sourceLevel >= ClassFileConstants.JDK1_8) { // 7.5.3 says nothing about collision of single static imports and JDK8 tolerates them, // though use is flagged. for (int j = 0; j < this.importPtr; j++) { ImportBinding resolved = this.tempImports[j]; if (resolved.isStatic() && resolved.resolvedImport instanceof ReferenceBinding && importBinding != resolved.resolvedImport) { if (CharOperation.equals( name, resolved.compoundName[resolved.compoundName.length - 1])) { ReferenceBinding type = (ReferenceBinding) resolved.resolvedImport; resolved.resolvedImport = new ProblemReferenceBinding( new char[][] {name}, type, ProblemReasons.Ambiguous); return -1; } } } } problemReporter().duplicateImport(importReference); return -1; } typesBySimpleNames.put(name, referenceBinding); } else if (importBinding instanceof FieldBinding) { for (int j = 0; j < this.importPtr; j++) { ImportBinding resolved = this.tempImports[j]; // find other static fields with the same name if (resolved.isStatic() && resolved.resolvedImport instanceof FieldBinding && importBinding != resolved.resolvedImport) { if (CharOperation.equals(name, resolved.compoundName[resolved.compoundName.length - 1])) { if (compilerOptions().sourceLevel >= ClassFileConstants.JDK1_8) { // 7.5.3 says nothing about collision of single static imports and JDK8 tolerates // them, though use is flagged. FieldBinding field = (FieldBinding) resolved.resolvedImport; resolved.resolvedImport = new ProblemFieldBinding( field, field.declaringClass, name, ProblemReasons.Ambiguous); return -1; } else { problemReporter().duplicateImport(importReference); return -1; } } } } } if (conflictingType == null) { recordImportBinding(new ImportBinding(compoundName, false, importBinding, importReference)); } else { recordImportBinding( new ImportConflictBinding(compoundName, importBinding, conflictingType, importReference)); } return this.importPtr; }
void buildTypeBindings(AccessRestriction accessRestriction) { this.topLevelTypes = new SourceTypeBinding[0]; // want it initialized if the package cannot be resolved boolean firstIsSynthetic = false; if (this.referenceContext.compilationResult.compilationUnit != null) { char[][] expectedPackageName = this.referenceContext.compilationResult.compilationUnit.getPackageName(); if (expectedPackageName != null && !CharOperation.equals(this.currentPackageName, expectedPackageName)) { // only report if the unit isn't structurally empty if (this.referenceContext.currentPackage != null || this.referenceContext.types != null || this.referenceContext.imports != null) { problemReporter().packageIsNotExpectedPackage(this.referenceContext); } this.currentPackageName = expectedPackageName.length == 0 ? CharOperation.NO_CHAR_CHAR : expectedPackageName; } } if (this.currentPackageName == CharOperation.NO_CHAR_CHAR) { // environment default package is never null this.fPackage = this.environment.defaultPackage; } else { if ((this.fPackage = this.environment.createPackage(this.currentPackageName)) == null) { if (this.referenceContext.currentPackage != null) { problemReporter() .packageCollidesWithType( this.referenceContext); // only report when the unit has a package statement } // ensure fPackage is not null this.fPackage = this.environment.defaultPackage; return; } else if (this.referenceContext.isPackageInfo()) { // resolve package annotations now if this is "package-info.java". if (this.referenceContext.types == null || this.referenceContext.types.length == 0) { this.referenceContext.types = new TypeDeclaration[1]; this.referenceContext.createPackageInfoType(); firstIsSynthetic = true; } // ensure the package annotations are copied over before resolution if (this.referenceContext.currentPackage != null && this.referenceContext.currentPackage.annotations != null) { this.referenceContext.types[0].annotations = this.referenceContext.currentPackage.annotations; } } recordQualifiedReference(this.currentPackageName); // always dependent on your own package } // Skip typeDeclarations which know of previously reported errors TypeDeclaration[] types = this.referenceContext.types; int typeLength = (types == null) ? 0 : types.length; this.topLevelTypes = new SourceTypeBinding[typeLength]; int count = 0; nextType: for (int i = 0; i < typeLength; i++) { TypeDeclaration typeDecl = types[i]; if (this.environment.isProcessingAnnotations && this.environment.isMissingType(typeDecl.name)) throw new SourceTypeCollisionException(); // resolved a type ref before APT generated the // type ReferenceBinding typeBinding = this.fPackage.getType0(typeDecl.name); recordSimpleReference(typeDecl.name); // needed to detect collision cases if (typeBinding != null && typeBinding.isValidBinding() && !(typeBinding instanceof UnresolvedReferenceBinding)) { // if its an unresolved binding - its fixed up whenever its needed, see // UnresolvedReferenceBinding.resolve() if (this.environment.isProcessingAnnotations) throw new SourceTypeCollisionException(); // resolved a type ref before APT generated the // type // if a type exists, check that its a valid type // it can be a NotFound problem type if its a secondary type referenced before its primary // type found in additional units // and it can be an unresolved type which is now being defined problemReporter().duplicateTypes(this.referenceContext, typeDecl); continue nextType; } if (this.fPackage != this.environment.defaultPackage && this.fPackage.getPackage(typeDecl.name) != null) { // if a package exists, it must be a valid package - cannot be a NotFound problem package // this is now a warning since a package does not really 'exist' until it contains a type, // see JLS v2, 7.4.3 problemReporter().typeCollidesWithPackage(this.referenceContext, typeDecl); } if ((typeDecl.modifiers & ClassFileConstants.AccPublic) != 0) { char[] mainTypeName; if ((mainTypeName = this.referenceContext.getMainTypeName()) != null // mainTypeName == null means that implementor of ICompilationUnit decided // to return null && !CharOperation.equals(mainTypeName, typeDecl.name)) { problemReporter().publicClassMustMatchFileName(this.referenceContext, typeDecl); // tolerate faulty main type name (91091), allow to proceed into type construction } } ClassScope child = new ClassScope(this, typeDecl); SourceTypeBinding type = child.buildType(null, this.fPackage, accessRestriction); if (firstIsSynthetic && i == 0) type.modifiers |= ClassFileConstants.AccSynthetic; if (type != null) this.topLevelTypes[count++] = type; } // shrink topLevelTypes... only happens if an error was reported if (count != this.topLevelTypes.length) System.arraycopy( this.topLevelTypes, 0, this.topLevelTypes = new SourceTypeBinding[count], 0, count); }
/* * INTERNAL USE-ONLY * Innerclasses get their name computed as they are generated, since some may not * be actually outputed if sitting inside unreachable code. */ public char[] computeConstantPoolName(LocalTypeBinding localType) { if (localType.constantPoolName != null) { return localType.constantPoolName; } // delegates to the outermost enclosing classfile, since it is the only one with a global vision // of its innertypes. if (this.constantPoolNameUsage == null) this.constantPoolNameUsage = new HashtableOfType(); ReferenceBinding outerMostEnclosingType = localType.scope.outerMostClassScope().enclosingSourceType(); // ensure there is not already such a local type name defined by the user int index = 0; char[] candidateName; boolean isCompliant15 = compilerOptions().complianceLevel >= ClassFileConstants.JDK1_5; while (true) { if (localType.isMemberType()) { if (index == 0) { candidateName = CharOperation.concat( localType.enclosingType().constantPoolName(), localType.sourceName, '$'); } else { // in case of collision, then member name gets extra $1 inserted // e.g. class X { { class L{} new X(){ class L{} } } } candidateName = CharOperation.concat( localType.enclosingType().constantPoolName(), '$', String.valueOf(index).toCharArray(), '$', localType.sourceName); } } else if (localType.isAnonymousType()) { if (isCompliant15) { // AspectJ Extension start char[] extraInsert = null; if (outerMostEnclosingType instanceof SourceTypeBinding) { SourceTypeBinding sourceTypeBinding = (SourceTypeBinding) outerMostEnclosingType; ClassScope classScope = sourceTypeBinding.scope; if (classScope != null) { TypeDeclaration typeDeclaration = classScope.referenceContext; if (typeDeclaration != null) { extraInsert = typeDeclaration.getLocalTypeNameSuffix(); } } } if (extraInsert != null) { // AspectJ Extension end candidateName = CharOperation.concat( localType.enclosingType.constantPoolName(), '$', extraInsert, '$', String.valueOf(index + 1).toCharArray()); } else { // from 1.5 on, use immediately enclosing type name candidateName = CharOperation.concat( localType.enclosingType.constantPoolName(), String.valueOf(index + 1).toCharArray(), '$'); } // AspectJ extension, closing } } else { candidateName = CharOperation.concat( outerMostEnclosingType.constantPoolName(), String.valueOf(index + 1).toCharArray(), '$'); } } else { // local type if (isCompliant15) { candidateName = CharOperation.concat( CharOperation.concat( localType.enclosingType().constantPoolName(), String.valueOf(index + 1).toCharArray(), '$'), localType.sourceName); } else { candidateName = CharOperation.concat( outerMostEnclosingType.constantPoolName(), '$', String.valueOf(index + 1).toCharArray(), '$', localType.sourceName); } } if (this.constantPoolNameUsage.get(candidateName) != null) { index++; } else { this.constantPoolNameUsage.put(candidateName, localType); break; } } return candidateName; }