diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/corrections/proposals/NewCUProposal.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/corrections/proposals/NewCUProposal.java index b67af76452..42f1935215 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/corrections/proposals/NewCUProposal.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/corrections/proposals/NewCUProposal.java @@ -17,6 +17,7 @@ *******************************************************************************/ package org.eclipse.jdt.ls.core.internal.corrections.proposals; +import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import java.util.Objects; @@ -76,8 +77,6 @@ public class NewCUProposal extends ChangeCorrectionProposal { private int fTypeKind; private IJavaElement fTypeContainer; // IType or IPackageFragment private String fTypeNameWithParameters; - private IType fCreatedType; - /** * Construct a new compilation unit proposal. * @@ -391,22 +390,32 @@ private String constructCUContent(ICompilationUnit cu, String typeContent, Strin * Called from createType to construct the source for this type */ private String constructTypeStub(ICompilationUnit parentCU, String name, int modifiers, String lineDelimiter) throws CoreException { - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); buf.append(Flags.toString(modifiers)); if (modifiers != 0) { buf.append(' '); } + + String[] permittedNames = fCompilationUnit.findPrimaryType().getPermittedSubtypeNames(); + boolean isPermitted = Arrays.asList(permittedNames).stream().anyMatch(p -> name.equals(p)); + if (isPermitted) { + buf.append("final "); + } + String type = ""; //$NON-NLS-1$ String templateID = ""; //$NON-NLS-1$ + String superType = ""; //$NON-NLS-1$ switch (fTypeKind) { case K_CLASS: type = "class "; //$NON-NLS-1$ templateID = CodeGeneration.CLASS_BODY_TEMPLATE_ID; + superType = fCompilationUnit.findPrimaryType().isInterface() ? "implements " : "extends "; break; case K_INTERFACE: type = "interface "; //$NON-NLS-1$ templateID = CodeGeneration.INTERFACE_BODY_TEMPLATE_ID; + superType = "extends "; break; case K_ENUM: type = "enum "; //$NON-NLS-1$ @@ -419,6 +428,11 @@ private String constructTypeStub(ICompilationUnit parentCU, String name, int mod } buf.append(type); buf.append(name); + if (isPermitted) { + buf.append(' '); + buf.append(superType); + buf.append(fCompilationUnit.findPrimaryType().getElementName()); + } buf.append(" {").append(lineDelimiter); //$NON-NLS-1$ String typeBody = CodeGeneration.getTypeBody(templateID, parentCU, name, lineDelimiter); diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/corrections/proposals/UnresolvedElementsSubProcessor.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/corrections/proposals/UnresolvedElementsSubProcessor.java index 9b8b45b4cc..b966582951 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/corrections/proposals/UnresolvedElementsSubProcessor.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/corrections/proposals/UnresolvedElementsSubProcessor.java @@ -550,6 +550,23 @@ private static boolean hasFieldWithName(ITypeBinding typeBinding, String name) { private static int evauateTypeKind(ASTNode node, IJavaProject project) { int kind = ASTResolving.getPossibleTypeKinds(node, JavaModelUtil.is50OrHigher(project)); + + /* + * TODO : This code block should be contributed to ASTResolving.getPossibleTypeKinds(..) + * Support determining type of the 'permits' node type. + */ + ASTNode parent = node.getParent(); + if (parent instanceof Type) { + Type type = (Type) parent; + TypeDeclaration typeDecl = ASTNodes.getParent(node, TypeDeclaration.class); + if (type.getLocationInParent() == TypeDeclaration.PERMITS_TYPES_PROPERTY) { + kind = TypeKinds.CLASSES; + if (typeDecl != null && typeDecl.isInterface()) { + kind |= TypeKinds.INTERFACES; + } + } + } + return kind; } diff --git a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/correction/UnresolvedTypesQuickFixTest.java b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/correction/UnresolvedTypesQuickFixTest.java index dc69a741a4..75e9305293 100644 --- a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/correction/UnresolvedTypesQuickFixTest.java +++ b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/correction/UnresolvedTypesQuickFixTest.java @@ -16,8 +16,10 @@ package org.eclipse.jdt.ls.core.internal.correction; import java.util.ArrayList; +import java.util.HashMap; import java.util.Hashtable; import java.util.List; +import java.util.Map; import org.eclipse.core.runtime.Path; import org.eclipse.jdt.core.IClasspathAttribute; @@ -26,6 +28,7 @@ import org.eclipse.jdt.core.IPackageFragment; import org.eclipse.jdt.core.IPackageFragmentRoot; import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.internal.corext.util.JavaModelUtil; import org.eclipse.jdt.ls.core.internal.JavaProjectHelper; import org.junit.Before; import org.junit.Ignore; @@ -1400,4 +1403,30 @@ public void testDontImportTestClassesInMainCode() throws Exception { assertCodeActionNotExists(cu1, "Import 'Tests' (pt)"); } + @Test + public void testTypeInSealedTypeDeclaration() throws Exception { + Map options15 = new HashMap<>(); + JavaModelUtil.setComplianceOptions(options15, JavaCore.VERSION_15); + options15.put(JavaCore.COMPILER_PB_ENABLE_PREVIEW_FEATURES, JavaCore.ENABLED); + options15.put(JavaCore.COMPILER_PB_REPORT_PREVIEW_FEATURES, JavaCore.IGNORE); + fJProject1.setOptions(options15); + + IPackageFragment pack1 = fSourceFolder.createPackageFragment("test1", false, null); + StringBuilder buf = new StringBuilder(); + buf.append("package test1;\n"); + buf.append("public sealed interface E permits F {\n"); + buf.append("}\n"); + ICompilationUnit cu = pack1.createCompilationUnit("E.java", buf.toString(), false, null); + + buf = new StringBuilder(); + buf.append("package test1;\n"); + buf.append("\n"); + buf.append("public final class F implements E {\n"); + buf.append("\n"); + buf.append("}\n"); + Expected e1 = new Expected("Create class 'F'", buf.toString()); + + assertCodeActions(cu, e1); + } + } \ No newline at end of file