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 98a58b10a9c..8220ebce817 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 @@ -32,13 +32,9 @@ *******************************************************************************/ package org.eclipse.jdt.internal.compiler.lookup; -import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; -import java.util.LinkedHashSet; -import java.util.List; import java.util.Map; -import java.util.Set; import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.internal.compiler.ast.*; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; @@ -115,8 +111,6 @@ void buildAnonymousTypeBinding(SourceTypeBinding enclosingType, ReferenceBinding } else { anonymousType.setSuperClass(supertype); anonymousType.setSuperInterfaces(Binding.NO_SUPERINTERFACES); - 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; @@ -152,21 +146,6 @@ void buildAnonymousTypeBinding(SourceTypeBinding enclosingType, ReferenceBinding anonymousType.verifyMethods(environment().methodVerifier()); } - 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); - } - } - void buildComponents() { SourceTypeBinding sourceType = this.referenceContext.binding; if (!sourceType.isRecord()) return; @@ -368,7 +347,6 @@ void buildLocalTypeBinding(SourceTypeBinding enclosingType) { LocalTypeBinding localType = buildLocalType(enclosingType, enclosingType.fPackage); connectTypeHierarchy(); - connectImplicitPermittedTypes(); if (compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5) { checkParameterizedTypeBounds(); checkParameterizedSuperTypeCollisions(); @@ -1267,49 +1245,12 @@ private boolean connectEnumSuperclass() { } return !foundCycle; } - private void connectImplicitPermittedTypes(SourceTypeBinding sourceType) { - List types = new ArrayList<>(); - for (TypeDeclaration typeDecl : this.referenceCompilationUnit().types) { - types.addAll(sourceType.collectAllTypeBindings(typeDecl, this.compilationUnitScope())); - } - Set permSubTypes = new LinkedHashSet<>(); - for (ReferenceBinding type : types) { - if (!TypeBinding.equalsEquals(type, sourceType) && type.findSuperTypeOriginatingFrom(sourceType) != null) { - permSubTypes.add(type); - } - } - if (sourceType.isSealed() && sourceType.isLocalType()) { - // bug xxxx flag Error and return; - } - if (permSubTypes.size() == 0) { - if (!sourceType.isLocalType() && !sourceType.isRecord() && !sourceType.isEnum()) // error flagged already - problemReporter().sealedSealedTypeMissingPermits(sourceType, this.referenceContext); - return; - } - sourceType.setPermittedTypes(permSubTypes.toArray(new ReferenceBinding[0])); - } - void connectImplicitPermittedTypes() { - TypeDeclaration typeDecl = this.referenceContext; - SourceTypeBinding sourceType = typeDecl.binding; - if (sourceType.id == TypeIds.T_JavaLangObject) // already handled - return; - if (sourceType.isSealed() && (typeDecl.permittedTypes == null || - typeDecl.permittedTypes.length == 0 || typeDecl.permittedTypes[0].isImplicit())) { - connectImplicitPermittedTypes(sourceType); - } - ReferenceBinding[] memberTypes = sourceType.memberTypes; - if (memberTypes != null && memberTypes != Binding.NO_MEMBER_TYPES) { - for (ReferenceBinding memberType : memberTypes) - ((SourceTypeBinding) memberType).scope.connectImplicitPermittedTypes(); - } - } + void connectPermittedTypes() { SourceTypeBinding sourceType = this.referenceContext.binding; - sourceType.setPermittedTypes(Binding.NO_PERMITTED_TYPES); - if (sourceType.id == TypeIds.T_JavaLangObject || sourceType.isEnum()) // already handled - return; - if (this.referenceContext.permittedTypes != null) { + if (this.referenceContext.permittedTypes != null && !this.referenceContext.permittedTypes[0].isImplicit()) { + sourceType.setPermittedTypes(Binding.NO_PERMITTED_TYPES); try { sourceType.tagBits |= TagBits.SealingTypeHierarchy; int length = this.referenceContext.permittedTypes.length; @@ -1340,6 +1281,15 @@ void connectPermittedTypes() { } finally { sourceType.tagBits &= ~TagBits.SealingTypeHierarchy; } + } else { + ReferenceBinding[] permittedTypes = sourceType.permittedTypes(); + if (permittedTypes == null || permittedTypes.length == 0) { + sourceType.setPermittedTypes(Binding.NO_PERMITTED_TYPES); + if (sourceType.isSealed()) { + if (!sourceType.isLocalType() && !sourceType.isRecord() && !sourceType.isEnum()) // error flagged alread + problemReporter().sealedSealedTypeMissingPermits(sourceType, this.referenceContext); + } + } } ReferenceBinding[] memberTypes = sourceType.memberTypes; if (memberTypes != null && memberTypes != Binding.NO_MEMBER_TYPES) { diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/CompilationUnitScope.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/CompilationUnitScope.java index efb8efd3bc1..1f646063e7f 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/CompilationUnitScope.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/CompilationUnitScope.java @@ -426,8 +426,6 @@ void sealTypeHierarchy() { for (SourceTypeBinding sourceType : this.topLevelTypes) { sourceType.scope.connectPermittedTypes(); } - for (SourceTypeBinding topLevelType : this.topLevelTypes) - topLevelType.scope.connectImplicitPermittedTypes(); } void integrateAnnotationsInHierarchy() { // Only now that all hierarchy information is built we're ready for ... 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 d62f5165843..bcd09746c9a 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 @@ -67,7 +67,6 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.ASTVisitor; import org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy; import org.eclipse.jdt.internal.compiler.ast.*; import org.eclipse.jdt.internal.compiler.ast.TypeReference.AnnotationPosition; @@ -1277,40 +1276,6 @@ private void reportSealedSuperTypeDoesNotPermitProblem(TypeReference superTypeRe } } -public List collectAllTypeBindings(TypeDeclaration typeDecl, CompilationUnitScope unitScope) { - class TypeBindingsCollector extends ASTVisitor { - List types = new ArrayList<>(); - @Override - public boolean visit( - TypeDeclaration localTypeDeclaration, - BlockScope scope1) { - checkAndAddBinding(localTypeDeclaration.binding); - return true; - } - @Override - public boolean visit( - TypeDeclaration memberTypeDeclaration, - ClassScope scope1) { - checkAndAddBinding(memberTypeDeclaration.binding); - return true; - } - @Override - public boolean visit( - TypeDeclaration typeDeclaration, - CompilationUnitScope scope1) { - checkAndAddBinding(typeDeclaration.binding); - return true; // do nothing by default, keep traversing - } - private void checkAndAddBinding(SourceTypeBinding stb) { - if (stb != null) - this.types.add(stb); - } - } - TypeBindingsCollector typeCollector = new TypeBindingsCollector(); - typeDecl.traverse(typeCollector, unitScope); - return typeCollector.types; -} - private boolean checkPermitsAndAdd(ReferenceBinding superType) { if (superType == null || superType.equals(this.scope.getJavaLangObject()) @@ -3263,9 +3228,31 @@ public ReferenceBinding setSuperClass(ReferenceBinding superClass) { annotatedType.superclass = superClass; } } + if (superClass != null && superClass.actualType() instanceof SourceTypeBinding sourceSuperType && sourceSuperType.isSealed() + && (sourceSuperType.scope.referenceContext.permittedTypes == null || sourceSuperType.scope.referenceContext.permittedTypes[0].isImplicit())) { + sourceSuperType.setImplicitPermittedType(this); + if (this.isAnonymousType() && superClass.isEnum()) + this.modifiers |= ClassFileConstants.AccFinal; + } return this.superclass = superClass; } +private void setImplicitPermittedType(SourceTypeBinding permittedType) { + ReferenceBinding[] typesPermitted = this.permittedTypes(); + int sz = typesPermitted == null ? 0 : typesPermitted.length; + if (this.scope.referenceCompilationUnit() == permittedType.scope.referenceCompilationUnit()) { + if (sz == 0) { + typesPermitted = new ReferenceBinding[] { permittedType }; + } else { + System.arraycopy(typesPermitted, 0, typesPermitted = new ReferenceBinding[sz + 1], 0, sz); + typesPermitted[sz] = permittedType; + } + this.setPermittedTypes(typesPermitted); + } else if (sz == 0) { + this.setPermittedTypes(Binding.NO_PERMITTED_TYPES); + } +} + // Propagate writes to all annotated variants so the clones evolve along. public ReferenceBinding [] setSuperInterfaces(ReferenceBinding [] superInterfaces) { @@ -3279,6 +3266,13 @@ public ReferenceBinding setSuperClass(ReferenceBinding superClass) { annotatedType.superInterfaces = superInterfaces; } } + for (int i = 0, length = superInterfaces == null ? 0 : superInterfaces.length; i < length; i++) { + ReferenceBinding superInterface = superInterfaces[i]; + if (superInterface.actualType() instanceof SourceTypeBinding sourceSuperType && sourceSuperType.isSealed() + && (sourceSuperType.scope.referenceContext.permittedTypes == null || sourceSuperType.scope.referenceContext.permittedTypes[0].isImplicit())) { + sourceSuperType.setImplicitPermittedType(this); + } + } return this.superInterfaces = superInterfaces; } diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SealedTypesTests.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SealedTypesTests.java index 470cc748475..79c0e51e9a6 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SealedTypesTests.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SealedTypesTests.java @@ -1579,8 +1579,8 @@ public void testBug564498_2() throws IOException, ClassFormatException { ""); String expectedOutput = "PermittedSubclasses:\n" + - " #22 p1/A$Z,\n" + - " #24 p1/A$SubY\n" + + " #22 p1/A$SubY,\n" + + " #24 p1/A$Z\n" + "}"; verifyClassFile(expectedOutput, "p1/A$Y.class", ClassFileBytesDisassembler.SYSTEM); expectedOutput = @@ -1607,9 +1607,9 @@ public void testBug564498_3() throws IOException, ClassFormatException { ""); String expectedOutput = "PermittedSubclasses:\n" + - " #24 p1/A$Y$SubInnerY,\n" + - " #26 p1/A$Z,\n" + - " #28 p1/A$SubY\n"; + " #24 p1/A$SubY,\n" + + " #26 p1/A$Y$SubInnerY,\n" + + " #28 p1/A$Z\n"; verifyClassFile(expectedOutput, "p1/A$Y.class", ClassFileBytesDisassembler.SYSTEM); } public void testBug564498_4() throws IOException, ClassFormatException {