diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ClassFile.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ClassFile.java index 1dc5edb52cf..e254e3af717 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ClassFile.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ClassFile.java @@ -385,8 +385,7 @@ else if (this.referenceBinding.isAnnotationType()) attributesNumber += generateBootstrapMethods(this.bootstrapMethods); } if (this.targetJDK >= ClassFileConstants.JDK17) { - // add record attributes - attributesNumber += generatePermittedTypeAttributes(); + attributesNumber += generatePermittedSubclassesAttribute(); } // Inner class attribute int numberOfInnerClasses = this.innerClassesBindings == null ? 0 : this.innerClassesBindings.size(); @@ -2852,10 +2851,9 @@ private int generateNestAttributes() { nAttrs += generateNestHostAttribute(); return nAttrs; } - private int generatePermittedTypeAttributes() { - SourceTypeBinding type = this.referenceBinding; + private int generatePermittedSubclassesAttribute() { int localContentsOffset = this.contentsOffset; - ReferenceBinding[] permittedTypes = type.permittedTypes(); + ReferenceBinding[] permittedTypes = this.referenceBinding.permittedTypes(); int l = permittedTypes != null ? permittedTypes.length : 0; if (l == 0) return 0; @@ -2864,6 +2862,14 @@ private int generatePermittedTypeAttributes() { if (exSize + localContentsOffset >= this.contents.length) { resizeContents(exSize); } + /* + * PermittedSubclasses_attribute { + u2 attribute_name_index; + u4 attribute_length; + u2 number_of_classes; + u2 classes[number_of_classes]; + } + */ int attributeNameIndex = this.constantPool.literalIndex(AttributeNamesConstants.PermittedSubclasses); this.contents[localContentsOffset++] = (byte) (attributeNameIndex >> 8); diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java index da082598e36..8cd977bb712 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java @@ -438,7 +438,7 @@ void cachePartsFrom(IBinaryType binaryType, boolean needFieldsAndMethods) { // and still want to use binaries passed that point (e.g. type hierarchy resolver, see bug 63748). this.typeVariables = Binding.NO_TYPE_VARIABLES; this.superInterfaces = Binding.NO_SUPERINTERFACES; - this.permittedTypes = Binding.NO_PERMITTEDTYPES; + this.permittedTypes = Binding.NO_PERMITTED_TYPES; // must retrieve member types in case superclass/interfaces need them this.memberTypes = Binding.NO_MEMBER_TYPES; @@ -2632,7 +2632,7 @@ public String toString() { } if (this.permittedTypes != null) { - if (this.permittedTypes != Binding.NO_PERMITTEDTYPES) { + if (this.permittedTypes != Binding.NO_PERMITTED_TYPES) { buffer.append("\n\tpermits : "); //$NON-NLS-1$ for (int i = 0, length = this.permittedTypes.length; i < length; i++) { if (i > 0) diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/Binding.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/Binding.java index 34073261c30..c1beb405a48 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/Binding.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/Binding.java @@ -62,7 +62,7 @@ public abstract class Binding { public static final ReferenceBinding[] ANY_EXCEPTION = new ReferenceBinding[] { null }; // special handler for all exceptions public static final FieldBinding[] NO_FIELDS = new FieldBinding[0]; public static final MethodBinding[] NO_METHODS = new MethodBinding[0]; - public static final ReferenceBinding[] NO_PERMITTEDTYPES = new ReferenceBinding[0]; + public static final ReferenceBinding[] NO_PERMITTED_TYPES = new ReferenceBinding[0]; public static final ReferenceBinding[] NO_SUPERINTERFACES = new ReferenceBinding[0]; public static final ReferenceBinding[] NO_MEMBER_TYPES = new ReferenceBinding[0]; public static final TypeVariableBinding[] NO_TYPE_VARIABLES = new TypeVariableBinding[0]; diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java index c5fa32650d8..98a58b10a9c 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java @@ -95,7 +95,7 @@ void buildAnonymousTypeBinding(SourceTypeBinding enclosingType, ReferenceBinding } } anonymousType.typeBits |= inheritedBits; - anonymousType.setPermittedTypes(Binding.NO_PERMITTEDTYPES); // JLS 15 JEP 360 Preview - Sec 15.9.5 + anonymousType.setPermittedTypes(Binding.NO_PERMITTED_TYPES); if (supertype.isInterface()) { anonymousType.setSuperClass(getJavaLangObject()); anonymousType.setSuperInterfaces(new ReferenceBinding[] { supertype }); @@ -115,7 +115,8 @@ void buildAnonymousTypeBinding(SourceTypeBinding enclosingType, ReferenceBinding } else { anonymousType.setSuperClass(supertype); anonymousType.setSuperInterfaces(Binding.NO_SUPERINTERFACES); - checkForEnumSealedPreview(supertype, anonymousType); + if (supertype.isEnum() && supertype instanceof SourceTypeBinding superEnum) + implicitlySealEnumHierarchy(superEnum, anonymousType); TypeReference typeReference = this.referenceContext.allocation.type; if (typeReference != null) { // no check for enum constant body this.referenceContext.superclass = typeReference; @@ -151,25 +152,19 @@ void buildAnonymousTypeBinding(SourceTypeBinding enclosingType, ReferenceBinding anonymousType.verifyMethods(environment().methodVerifier()); } - private void checkForEnumSealedPreview(ReferenceBinding supertype, LocalTypeBinding anonymousType) { - if (!JavaFeature.SEALED_CLASSES.isSupported(compilerOptions()) - || !supertype.isEnum() - || !(supertype instanceof SourceTypeBinding)) - return; - - SourceTypeBinding sourceSuperType = (SourceTypeBinding) supertype; - ReferenceBinding[] permTypes = sourceSuperType.permittedTypes(); - int sz = permTypes == null ? 0 : permTypes.length; - if (sz == 0) { - permTypes = new ReferenceBinding[] {anonymousType}; - } else { - System.arraycopy(permTypes, 0, - permTypes = new ReferenceBinding[sz + 1], 0, - sz); - permTypes[sz] = anonymousType; + private void implicitlySealEnumHierarchy(SourceTypeBinding superEnum, LocalTypeBinding anonymousType) { + if (JavaFeature.SEALED_CLASSES.isSupported(compilerOptions())) { + ReferenceBinding[] permittedTypes = superEnum.permittedTypes(); + int sz = permittedTypes == null ? 0 : permittedTypes.length; + if (sz == 0) { + permittedTypes = new ReferenceBinding[] { anonymousType }; + } else { + System.arraycopy(permittedTypes, 0, permittedTypes = new ReferenceBinding[sz + 1], 0, sz); + permittedTypes[sz] = anonymousType; + } + anonymousType.modifiers |= ClassFileConstants.AccFinal; + superEnum.setPermittedTypes(permittedTypes); } - anonymousType.modifiers |= ClassFileConstants.AccFinal; // JLS 15 / sealed preview/Sec 8.9.1 - sourceSuperType.setPermittedTypes(permTypes); } void buildComponents() { @@ -1183,7 +1178,7 @@ private boolean connectSuperclass() { if (sourceType.id == TypeIds.T_JavaLangObject) { // handle the case of redefining java.lang.Object up front sourceType.setSuperClass(null); sourceType.setSuperInterfaces(Binding.NO_SUPERINTERFACES); - sourceType.setPermittedTypes(Binding.NO_PERMITTEDTYPES); + sourceType.setPermittedTypes(Binding.NO_PERMITTED_TYPES); if (!sourceType.isClass()) problemReporter().objectMustBeClass(sourceType); if (this.referenceContext.superclass != null || (this.referenceContext.superInterfaces != null && this.referenceContext.superInterfaces.length > 0)) @@ -1310,7 +1305,7 @@ void connectImplicitPermittedTypes() { } void connectPermittedTypes() { SourceTypeBinding sourceType = this.referenceContext.binding; - sourceType.setPermittedTypes(Binding.NO_PERMITTEDTYPES); + sourceType.setPermittedTypes(Binding.NO_PERMITTED_TYPES); if (sourceType.id == TypeIds.T_JavaLangObject || sourceType.isEnum()) // already handled return; @@ -1323,30 +1318,24 @@ void connectPermittedTypes() { nextPermittedType : for (int i = 0; i < length; i++) { TypeReference permittedTypeRef = this.referenceContext.permittedTypes[i]; ReferenceBinding permittedType = findPermittedtype(permittedTypeRef); - if (permittedType == null) { // detected cycle + if (permittedType == null) { continue nextPermittedType; } - if (!isPermittedTypeInAllowedFormat(sourceType, permittedTypeRef, permittedType)) - continue nextPermittedType; - // check for simple interface collisions - // Check for a duplicate interface once the name is resolved, otherwise we may be confused (i.e. a.b.I and c.d.I) for (int j = 0; j < i; j++) { if (TypeBinding.equalsEquals(permittedTypeBindings[j], permittedType)) { - problemReporter().sealedDuplicateTypeInPermits(sourceType, permittedTypeRef, permittedType); + problemReporter().duplicatePermittedType(sourceType, permittedTypeRef, permittedType); continue nextPermittedType; } } - // only want to reach here when no errors are reported permittedTypeBindings[count++] = permittedType; } - // hold onto all correctly resolved superinterfaces if (count > 0) { if (count != length) System.arraycopy(permittedTypeBindings, 0, permittedTypeBindings = new ReferenceBinding[count], 0, count); sourceType.setPermittedTypes(permittedTypeBindings); } else { - sourceType.setPermittedTypes(Binding.NO_PERMITTEDTYPES); + sourceType.setPermittedTypes(Binding.NO_PERMITTED_TYPES); } } finally { sourceType.tagBits &= ~TagBits.SealingTypeHierarchy; @@ -1359,29 +1348,6 @@ void connectPermittedTypes() { } } - private boolean isPermittedTypeInAllowedFormat(SourceTypeBinding sourceType, TypeReference permittedTypeRef, - ReferenceBinding permittedType) { - if (!(permittedType.isMemberType() && permittedTypeRef instanceof SingleTypeReference)) - return true; - ReferenceBinding enclosingType = permittedType.enclosingType(); - while (enclosingType != null) { - if (TypeBinding.equalsEquals(sourceType, enclosingType)) { - CompilationUnitScope cu = this.compilationUnitScope(); - if (cu.imports != null || cu.imports.length > 0) { - for (ImportBinding ib : cu.imports) { - Binding resolvedImport = cu.resolveSingleImport(ib, Binding.TYPE); - if (resolvedImport instanceof TypeBinding && - TypeBinding.equalsEquals(permittedType, (TypeBinding) resolvedImport)) - return true; - } - } - return false; - } - enclosingType = enclosingType.enclosingType(); - } - return true; - } - private boolean connectRecordSuperclass() { SourceTypeBinding sourceType = this.referenceContext.binding; ReferenceBinding rootRecordType = getJavaLangRecord(); @@ -1675,7 +1641,7 @@ private ReferenceBinding findSupertype(TypeReference typeReference) { } catch (AbortCompilation e) { SourceTypeBinding sourceType = this.referenceContext.binding; if (sourceType.superInterfaces == null) sourceType.setSuperInterfaces(Binding.NO_SUPERINTERFACES); // be more resilient for hierarchies (144976) - if (sourceType.permittedTypes == null) sourceType.setPermittedTypes(Binding.NO_PERMITTEDTYPES); + if (sourceType.permittedTypes == null) sourceType.setPermittedTypes(Binding.NO_PERMITTED_TYPES); e.updateContext(typeReference, referenceCompilationUnit().compilationResult); throw e; } finally { @@ -1703,7 +1669,7 @@ private ReferenceBinding findPermittedtype(TypeReference typeReference) { return permittedType != null ? permittedType.actualType() : permittedType; // while permitted classes/interfaces cannot be parameterized with type arguments, they are not raw either } catch (AbortCompilation e) { SourceTypeBinding sourceType = this.referenceContext.binding; - if (sourceType.permittedTypes == null) sourceType.setPermittedTypes(Binding.NO_PERMITTEDTYPES); + if (sourceType.permittedTypes == null) sourceType.setPermittedTypes(Binding.NO_PERMITTED_TYPES); e.updateContext(typeReference, referenceCompilationUnit().compilationResult); throw e; } finally { diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/MissingTypeBinding.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/MissingTypeBinding.java index 7a7ebab30bd..2356f8a0f2f 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/MissingTypeBinding.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/MissingTypeBinding.java @@ -34,7 +34,7 @@ public MissingTypeBinding(PackageBinding packageBinding, char[][] compoundName, this.modifiers = ClassFileConstants.AccPublic; this.superclass = null; // will be fixed up using #setMissingSuperclass(...) this.superInterfaces = Binding.NO_SUPERINTERFACES; - this.permittedTypes = Binding.NO_PERMITTEDTYPES; + this.permittedTypes = Binding.NO_PERMITTED_TYPES; this.typeVariables = Binding.NO_TYPE_VARIABLES; this.memberTypes = Binding.NO_MEMBER_TYPES; this.fields = Binding.NO_FIELDS; diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java index ed0ed1d538c..703ce2d7d26 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java @@ -3240,7 +3240,7 @@ public RecordComponentBinding[] setComponents(RecordComponentBinding[] comps) { return this.methods = methods; } -//Propagate writes to all annotated variants so the clones evolve along. +// Propagate writes to all annotated variants so the clones evolve along. public ReferenceBinding [] setPermittedTypes(ReferenceBinding [] permittedTypes) { if (!isPrototype()) diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/TypeBinding.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/TypeBinding.java index 314cbce802b..808d5b34985 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/TypeBinding.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/TypeBinding.java @@ -1759,7 +1759,7 @@ public ReferenceBinding superclass() { } public ReferenceBinding[] permittedTypes() { - return Binding.NO_PERMITTEDTYPES; + return Binding.NO_PERMITTED_TYPES; } public ReferenceBinding[] superInterfaces() { diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java index dbb8f40c7a5..3bb721eb34f 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java @@ -12336,7 +12336,7 @@ public void sealedMissingSealedModifier(SourceTypeBinding type, ASTNode node) { node.sourceEnd); } -public void sealedDuplicateTypeInPermits(SourceTypeBinding type, TypeReference reference, ReferenceBinding superType) { +public void duplicatePermittedType(SourceTypeBinding type, TypeReference reference, ReferenceBinding superType) { this.handle( IProblem.SealedDuplicateTypeInPermits, new String[] {