diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/ExtraCompilerModifiers.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/ExtraCompilerModifiers.java index c28b24760df..d509a5d8576 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/ExtraCompilerModifiers.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/ExtraCompilerModifiers.java @@ -45,14 +45,14 @@ public interface ExtraCompilerModifiers { // modifier constant final int AccUnresolved = ASTNode.Bit26; final int AccBlankFinal = ASTNode.Bit27; // for blank final variables final int AccIsDefaultConstructor = ASTNode.Bit27; // for default constructor - final int AccNonSealed = ASTNode.Bit27; // for class/interface + final int AccNonSealed = ASTNode.Bit29; // for class/interface final int AccLocallyUsed = ASTNode.Bit28; // used to diagnose unused (a) private/local members or (b) members of private classes // generally set when actual usage has been detected // or, (b) when member of a private class is exposed via a non-private subclass // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=328281 final int AccVisibilityMASK = ClassFileConstants.AccPublic | ClassFileConstants.AccProtected | ClassFileConstants.AccPrivate; - final int AccSealed = ASTNode.Bit29; // used for class/interface to set sealed + final int AccSealed = ASTNode.Bit26; // used for class/interface to set sealed final int AccOverriding = ASTNode.Bit29; // record fact a method overrides another one final int AccImplementing = ASTNode.Bit30; // record fact a method implements another one (it is concrete and overrides an abstract one) final int AccImplicitlyDeclared = ASTNode.Bit30; // used for implicitly declared classes diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java index 33286162ac6..d524682733d 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java @@ -1083,6 +1083,10 @@ public final int getAccessFlags() { return this.modifiers & ExtraCompilerModifiers.AccJustFlag; } +public final int getAccessFlagsForSealedAndNonSealed() { + return ((this.modifiers >>> 16) & 0xFFFF) & ExtraCompilerModifiers.AccJustFlag; +} + /** * @return the JSR 175 annotations for this type. */ diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverter_23Test.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverter_23Test.java index 9d389336f56..fa30479822a 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverter_23Test.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverter_23Test.java @@ -187,4 +187,35 @@ non-sealed class C extends A {} ITypeBinding aBinding = a.resolveBinding(); assertEquals("'non-sealed' modifier is not set in binding", Modifier.isNonSealed(aBinding.getModifiers()), true); } + + public void test003_c() throws CoreException { + ASTParser astParser = ASTParser.newParser(getAST23()); + Map options = new HashMap<>(); + options.put(JavaCore.COMPILER_COMPLIANCE, "23"); + options.put(JavaCore.COMPILER_SOURCE, "23"); + + astParser.setCompilerOptions(options); + astParser.setEnvironment(new String[] {}, new String[] {}, new String[] {}, true); + astParser.setUnitName("Example.java"); + astParser.setResolveBindings(true); + astParser.setBindingsRecovery(true); + + String source =""" + public sealed class A permits B, C {} + final class B extends A {} + non-sealed class C extends A {} + """; + + astParser.setSource(source.toCharArray()); + + CompilationUnit compilationUnit = (CompilationUnit) astParser.createAST(null); + TypeDeclaration a = (TypeDeclaration) compilationUnit.types().get(0); + + assertEquals("Modifier is not present in AST", Modifier.isSealed(a.getModifiers()), true); + + assertEquals("permitted types are not present in AST", a.permittedTypes().size(), 2); + + ITypeBinding aBinding = a.resolveBinding(); + assertEquals("'sealed' modifier is not set in binding", Modifier.isSealed(aBinding.getModifiers()), true); + } } diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TypeBinding.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TypeBinding.java index eb66f475de4..aa2030d518f 100644 --- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TypeBinding.java +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TypeBinding.java @@ -588,16 +588,13 @@ public int getKind() { public int getModifiers() { if (isClass()) { ReferenceBinding referenceBinding = (ReferenceBinding) this.binding; - int k = referenceBinding.getAccessFlags(); - final int accessFlags = k & VALID_MODIFIERS; + if (referenceBinding.isSealed() || referenceBinding.isNonSealed()) { + return referenceBinding.getAccessFlagsForSealedAndNonSealed(); + } + final int accessFlags = referenceBinding.getAccessFlags() & VALID_MODIFIERS; if (referenceBinding.isAnonymousType()) { return accessFlags & ~Modifier.FINAL; - } else if (referenceBinding.isSealed()) { - return Modifier.SEALED; - } else if (referenceBinding.isNonSealed()) { - return Modifier.NON_SEALED; } - return accessFlags; } else if (isAnnotation()) { ReferenceBinding referenceBinding = (ReferenceBinding) this.binding;