/* * 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; } } } }
/* * 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; }