Skip to content

Commit

Permalink
Created type doesn't implement sealed interface.
Browse files Browse the repository at this point in the history
- Add quick fix to generate proper type declaration for sealed type
- Fixes #1553
- Add testcase

Signed-off-by: Roland Grunberg <[email protected]>
  • Loading branch information
rgrunber authored and fbricon committed Oct 14, 2020
1 parent ece3235 commit e5ac0d8
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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.
*
Expand Down Expand Up @@ -391,22 +390,33 @@ 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(' ');
}

IType cuType = fCompilationUnit.findPrimaryType();
String[] permittedNames = cuType.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 = cuType.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$
Expand All @@ -419,6 +429,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(cuType.getElementName());
}

buf.append(" {").append(lineDelimiter); //$NON-NLS-1$
String typeBody = CodeGeneration.getTypeBody(templateID, parentCU, name, lineDelimiter);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -1400,4 +1403,30 @@ public void testDontImportTestClassesInMainCode() throws Exception {
assertCodeActionNotExists(cu1, "Import 'Tests' (pt)");
}

@Test
public void testTypeInSealedTypeDeclaration() throws Exception {
Map<String, String> 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);
}

}

0 comments on commit e5ac0d8

Please sign in to comment.