Bug 565782 - [15] sealed - flag enums implicitly sealed with enum
constants having anonymous classes

Change-Id: Idd14b620a950531ce4cd389c4182bf8c6aac31c2
Signed-off-by: Jay Arthanareeswaran <jarthana@in.ibm.com>
Also-by: Manoj Palat <manpalat@in.ibm.com>
diff --git a/org.eclipse.jdt.compiler.apt.tests/lib/apttestprocessors8.jar b/org.eclipse.jdt.compiler.apt.tests/lib/apttestprocessors8.jar
index a48e704..c1e9643 100644
--- a/org.eclipse.jdt.compiler.apt.tests/lib/apttestprocessors8.jar
+++ b/org.eclipse.jdt.compiler.apt.tests/lib/apttestprocessors8.jar
Binary files differ
diff --git a/org.eclipse.jdt.compiler.apt.tests/processors8/org/eclipse/jdt/compiler/apt/tests/processors/elements/BaseElementProcessor.java b/org.eclipse.jdt.compiler.apt.tests/processors8/org/eclipse/jdt/compiler/apt/tests/processors/elements/BaseElementProcessor.java
index d21e8a8..6cd7576 100644
--- a/org.eclipse.jdt.compiler.apt.tests/processors8/org/eclipse/jdt/compiler/apt/tests/processors/elements/BaseElementProcessor.java
+++ b/org.eclipse.jdt.compiler.apt.tests/processors8/org/eclipse/jdt/compiler/apt/tests/processors/elements/BaseElementProcessor.java
@@ -125,7 +125,7 @@
 
 	@Override
 	public void reportError(String msg) {
-		throw new AssertionFailedError(msg + " isBinary: " + isBinaryMode);
+		throw new AssertionFailedError(msg + " (Binary mode= " + isBinaryMode + ")");
 	}
 	protected String getExceptionStackTrace(Throwable t) {
 		StringBuffer buf = new StringBuffer(t.getMessage());
diff --git a/org.eclipse.jdt.compiler.apt.tests/processors8/org/eclipse/jdt/compiler/apt/tests/processors/elements/SealedTypeElementProcessor.java b/org.eclipse.jdt.compiler.apt.tests/processors8/org/eclipse/jdt/compiler/apt/tests/processors/elements/SealedTypeElementProcessor.java
index ec4d8dc..335cd41 100644
--- a/org.eclipse.jdt.compiler.apt.tests/processors8/org/eclipse/jdt/compiler/apt/tests/processors/elements/SealedTypeElementProcessor.java
+++ b/org.eclipse.jdt.compiler.apt.tests/processors8/org/eclipse/jdt/compiler/apt/tests/processors/elements/SealedTypeElementProcessor.java
@@ -26,6 +26,8 @@
 
 import javax.annotation.processing.ProcessingEnvironment;
 import javax.annotation.processing.SupportedAnnotationTypes;
+import javax.annotation.processing.SupportedSourceVersion;
+import javax.lang.model.SourceVersion;
 import javax.lang.model.element.Element;
 import javax.lang.model.element.ElementKind;
 import javax.lang.model.element.ExecutableElement;
@@ -36,6 +38,7 @@
 import javax.lang.model.type.TypeMirror;
 
 @SupportedAnnotationTypes("*")
+@SupportedSourceVersion(SourceVersion.RELEASE_15)
 public class SealedTypeElementProcessor extends BaseElementProcessor {
 	TypeElement nonSealed = null;
 	TypeElement sealed1 = null;
@@ -45,6 +48,7 @@
 	Modifier modifierFinal = null;
 	PackageElement topPkg = null;
 	PackageElement topPkg2 = null;
+	PackageElement topPkg3 = null;
 	@Override
 	public synchronized void init(ProcessingEnvironment processingEnv) {
 		super.init(processingEnv);
@@ -52,6 +56,10 @@
 	public void testAll() throws AssertionFailedError, IOException {
 		test001();
 		test002();
+		test003();
+		test004();
+		test005Src();
+		test005Binary();
 	}
 	private void fetchElements() {
 		Set<? extends Element> elements = roundEnv.getRootElements();
@@ -64,6 +72,8 @@
 				topPkg = (PackageElement) (element.getEnclosingElement());
 			} else if ("TopMain2".equals(element.getSimpleName().toString())) {
 				topPkg2 = (PackageElement) (element.getEnclosingElement());
+			} else if ("TopMain3".equals(element.getSimpleName().toString())) {
+				topPkg3 = (PackageElement) (element.getEnclosingElement());
 			}
 		}
 		try {
@@ -240,4 +250,56 @@
 			}
 		}
 	}
+	public void _test005() {
+		fetchElements();
+		assertNotNull("package null", topPkg3);
+		List<? extends Element> enclosedElements = topPkg3.getEnclosedElements();
+		assertEquals("incorrect no of enclosed elements", 1, enclosedElements.size());
+		TypeElement topType = null;
+		for (Element element : enclosedElements) {
+			if (element instanceof TypeElement) {
+				TypeElement temp = (TypeElement) element;
+				if (temp.getQualifiedName().toString().equals("sealed.sub3.TopMain3")) {
+					topType = (TypeElement) element;
+					break;
+				}
+			}
+		}
+		assertNotNull("type should not be null", topType);
+		enclosedElements = topType.getEnclosedElements();
+		assertEquals("incorrect no of enclosed elements", 4, enclosedElements.size());
+		TypeElement sealedIntf = null;
+		TypeElement enumElement = null;
+		for (Element element : enclosedElements) {
+			if (!(element instanceof TypeElement))
+				continue;
+			TypeElement typeEl = (TypeElement) element;
+			Set<Modifier> modifiers = null;
+			if (typeEl.getQualifiedName().toString().equals("sealed.sub3.TopMain3.SealedIntf")) {
+				sealedIntf = typeEl;
+				modifiers = typeEl.getModifiers();
+				assertTrue("should contain modifier sealed", modifiers.contains(sealed));
+				assertFalse("should not contain modifier final", modifiers.contains(modifierFinal));
+				assertTrue("should contain modifier static", modifiers.contains(modifierStatic));
+				assertFalse("should not contain modifier non-sealed", modifiers.contains(non_Sealed));
+			} else if (typeEl.getQualifiedName().toString().equals("sealed.sub3.TopMain3.MyEnum")) {
+				enumElement = typeEl;
+				modifiers = typeEl.getModifiers();
+				assertTrue("should contain modifier sealed", modifiers.contains(sealed));
+				assertFalse("enum should not contain modifier final", modifiers.contains(modifierFinal));
+				assertTrue("should contain modifier static", modifiers.contains(modifierStatic));
+				assertFalse("should not contain modifier non-sealed", modifiers.contains(non_Sealed));
+			}
+		}
+		assertNotNull("type element should not null", sealedIntf);
+		assertNotNull("type element should not null", enumElement);
+	}
+	public void test005Src() {
+		if (this.isBinaryMode) return;
+		_test005();
+	}	
+	public void test005Binary() {
+		if (!this.isBinaryMode) return;
+		_test005();
+	}
 }
diff --git a/org.eclipse.jdt.compiler.apt.tests/resources/mod_locations/sealed/mod.sealed.types/sealed/sub3/TopMain3.java b/org.eclipse.jdt.compiler.apt.tests/resources/mod_locations/sealed/mod.sealed.types/sealed/sub3/TopMain3.java
new file mode 100644
index 0000000..31b992a
--- /dev/null
+++ b/org.eclipse.jdt.compiler.apt.tests/resources/mod_locations/sealed/mod.sealed.types/sealed/sub3/TopMain3.java
@@ -0,0 +1,14 @@
+package sealed.sub3;
+
+public class TopMain3 {
+	TopMain3 top = new TopMain3() {};
+	sealed interface SealedIntf permits MyEnum {}
+	enum MyEnum implements SealedIntf{
+		 A {
+	            int val() { return 1; }
+	        }, B, C;
+	        int val() {
+	            return 0;
+	        }
+	}
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.compiler.apt.tests/src/org/eclipse/jdt/compiler/apt/tests/SealedTypeElementsTests.java b/org.eclipse.jdt.compiler.apt.tests/src/org/eclipse/jdt/compiler/apt/tests/SealedTypeElementsTests.java
index 3037cca..e76adac 100644
--- a/org.eclipse.jdt.compiler.apt.tests/src/org/eclipse/jdt/compiler/apt/tests/SealedTypeElementsTests.java
+++ b/org.eclipse.jdt.compiler.apt.tests/src/org/eclipse/jdt/compiler/apt/tests/SealedTypeElementsTests.java
@@ -60,12 +60,28 @@
 	}
 	public void test004() throws IOException {
 		JavaCompiler compiler = BatchTestUtils.getEclipseCompiler();
-		internalTestWithPreview(compiler, MODULE_PROC, "15", "test003", null, "sealed", true);
+		internalTestWithPreview(compiler, MODULE_PROC, "15", "test004", null, "sealed", true);
 	}
 	public void test004Javac() throws IOException {
 		JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
 		internalTestWithPreview(compiler, MODULE_PROC, "15", "test004", null, "sealed", true);
 	}
+	public void test005Src() throws IOException {
+		JavaCompiler compiler = BatchTestUtils.getEclipseCompiler();
+		internalTestWithPreview(compiler, MODULE_PROC, "15", "test005Src", null, "sealed", true);
+	}
+	public void test005SrcJavac() throws IOException {
+		JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
+		internalTestWithPreview(compiler, MODULE_PROC, "15", "test005Src", null, "sealed", true);
+	}
+	public void test005Binary() throws IOException {
+		JavaCompiler compiler = BatchTestUtils.getEclipseCompiler();
+		internalTestWithPreview(compiler, MODULE_PROC, "15", "test005Binary", null, "sealed", true);
+	}
+	public void test005BinaryJavac() throws IOException {
+		JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
+		internalTestWithPreview(compiler, MODULE_PROC, "15", "test005Binary", null, "sealed", true);
+	}
 
 	protected void internalTestWithPreview(JavaCompiler compiler, String processor, String compliance,
 			String testMethod, String testClass, String resourceArea, boolean preview) throws IOException {
diff --git a/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/model/Factory.java b/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/model/Factory.java
index bb37a01..e2d8107 100644
--- a/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/model/Factory.java
+++ b/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/model/Factory.java
@@ -313,7 +313,8 @@
 						ClassFileConstants.AccPrivate,
 						ClassFileConstants.AccAbstract,
 						ClassFileConstants.AccStatic,
-						ClassFileConstants.AccStrictfp
+						ClassFileConstants.AccStrictfp,
+						ExtraCompilerModifiers.AccSealed,
 					});
 				} else {
 					// enum from source cannot be explicitly abstract
@@ -323,7 +324,8 @@
 						ClassFileConstants.AccFinal,
 						ClassFileConstants.AccPrivate,
 						ClassFileConstants.AccStatic,
-						ClassFileConstants.AccStrictfp
+						ClassFileConstants.AccStrictfp,
+						ExtraCompilerModifiers.AccSealed,
 					});
 				}
 				break;
diff --git a/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/model/TypeElementImpl.java b/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/model/TypeElementImpl.java
index c334264..30df223 100644
--- a/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/model/TypeElementImpl.java
+++ b/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/model/TypeElementImpl.java
@@ -47,7 +47,6 @@
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
 import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
 import org.eclipse.jdt.internal.compiler.lookup.Binding;
-import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers;
 import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
 import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
 import org.eclipse.jdt.internal.compiler.lookup.RecordComponentBinding;
@@ -293,9 +292,6 @@
 		if (refBinding.isInterface() && refBinding.isNestedType()) {
 			modifiers |= ClassFileConstants.AccStatic;
 		}
-		if (refBinding.permittedTypes().length > 0) {
-			modifiers |= ExtraCompilerModifiers.AccSealed;
-		}
 		
 		return Factory.getModifiers(modifiers, getKind(), refBinding.isBinaryBinding());
 	}
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ClassFileReaderTest_15.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ClassFileReaderTest_15.java
index 38f94a4..a2ecb61 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ClassFileReaderTest_15.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ClassFileReaderTest_15.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2013, 2019 GoPivotal, Inc.
+ * Copyright (c) 2013, 2020 GoPivotal, Inc and others
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -22,6 +22,7 @@
 
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
+import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers;
 
 @SuppressWarnings({ "rawtypes" })
 public class ClassFileReaderTest_15 extends AbstractRegressionTest {
@@ -66,4 +67,48 @@
 		assertTrue(CharOperation.equals(permittedSubtypesNames, expected));
 
 	}
+	public void testBug565782_001() throws Exception {
+		String source =
+				"sealed interface I {}\n"+
+				"enum X implements I {\n"+
+				"    ONE {};\n"+
+				"    public static void main(String[] args) {\n"+
+				"        System.out.println(0);\n"+
+				"   }\n"+
+				"}";
+
+		org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader classFileReader = getInternalClassFile("", "X", "X", source);
+		char[][] permittedSubtypesNames = classFileReader.getPermittedSubtypeNames();
+
+		assertEquals(1, permittedSubtypesNames.length);
+
+		char [][] expected = {"X$1".toCharArray()};
+		assertTrue(CharOperation.equals(permittedSubtypesNames, expected));
+
+		int modifiers = classFileReader.getModifiers();
+		assertTrue("sealed modifier expected", (modifiers & ExtraCompilerModifiers.AccSealed) != 0);
+	}
+	public void testBug565782_002() throws Exception {
+		String source =
+				"sealed interface I {}\n"+
+				"class X {\n"+
+				"	enum E implements I {\n"+
+				"   	ONE {};\n"+
+				"	}\n"+
+				"   public static void main(String[] args) {\n"+
+				"      	System.out.println(0);\n"+
+				"   }\n"+
+				"}";
+
+		org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader classFileReader = getInternalClassFile("", "X.E", "X$E", source);
+		char[][] permittedSubtypesNames = classFileReader.getPermittedSubtypeNames();
+
+		assertEquals(1, permittedSubtypesNames.length);
+
+		char [][] expected = {"X$E$1".toCharArray()};
+		assertTrue(CharOperation.equals(permittedSubtypesNames, expected));
+
+		int modifiers = classFileReader.getModifiers();
+		assertTrue("sealed modifier expected", (modifiers & ExtraCompilerModifiers.AccSealed) != 0);
+	}
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileReader.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileReader.java
index 5a6d4e6..f1c9bfa 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileReader.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileReader.java
@@ -888,6 +888,8 @@
 	} else {
 		modifiers = this.accessFlags;
 	}
+	if (this.permittedSubtypesCount > 0)
+		modifiers |= ExtraCompilerModifiers.AccSealed;
 	return modifiers;
 }
 
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java
index 81b5912..e645ae7 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java
@@ -537,6 +537,7 @@
 			this.permittedSubtypes = Binding.NO_PERMITTEDTYPES;
 			char[][] permittedSubtypeNames = binaryType.getPermittedSubtypeNames();
 			if (permittedSubtypeNames != null) {
+				this.modifiers |= ExtraCompilerModifiers.AccSealed;
 				int size = permittedSubtypeNames.length;
 				if (size > 0) {
 					this.permittedSubtypes = new ReferenceBinding[size];
@@ -1671,12 +1672,6 @@
 }
 
 @Override
-public boolean isSealed() {
-	ReferenceBinding[] permittedSubTypes = permittedTypes();
-	return !(permittedSubTypes == null || permittedSubTypes == Binding.NO_PERMITTEDTYPES);
-}
-
-@Override
 public ReferenceBinding containerAnnotationType() {
 	if (!isPrototype()) throw new IllegalStateException();
 	if (this.containerAnnotationType instanceof UnresolvedReferenceBinding) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java
index f5a481e..f423dd2 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java
@@ -690,8 +690,9 @@
 			}
 			modifiers |= ClassFileConstants.AccAbstract;
 		} else if ((realModifiers & ClassFileConstants.AccEnum) != 0) {
-			boolean flagSealedNonModifiers = compilerOptions().sourceLevel >= ClassFileConstants.JDK15 &&
-					compilerOptions().enablePreviewFeatures &&
+			boolean isPreviewEnabled = compilerOptions().sourceLevel >= ClassFileConstants.JDK15 &&
+					compilerOptions().enablePreviewFeatures;
+			boolean flagSealedNonModifiers = isPreviewEnabled &&
 					(modifiers & (ExtraCompilerModifiers.AccSealed | ExtraCompilerModifiers.AccNonSealed)) != 0;
 			// detect abnormal cases for enums
 			if (isMemberType) { // includes member types defined inside local types
@@ -763,6 +764,8 @@
 					}
 					modifiers |= ClassFileConstants.AccFinal;
 				}
+				if (isPreviewEnabled && (modifiers & ClassFileConstants.AccFinal) == 0)
+					modifiers |= ExtraCompilerModifiers.AccSealed;
 			}
 		} else if (sourceType.isRecord()) {
 			if (isMemberType) {