From 14104906a806d3ae077871198bd6672ff4810b41 Mon Sep 17 00:00:00 2001 From: Roland Grunberg Date: Fri, 13 Dec 2024 15:28:16 -0500 Subject: [PATCH] Add quick fix for sealed class within empty switch expression. - When a sealed class is the target of an empty switch expression, add all the types it permits as case statements - Add testcase - Use upstream version of 'addTypeAsPermittedSubTypeProposal' Signed-off-by: Roland Grunberg --- .../corrections/QuickFixProcessor.java | 5 +- .../LocalCorrectionsSubProcessor.java | 156 ++++++++++++++++-- .../ModifierCorrectionsQuickFixTest.java | 46 ++++++ 3 files changed, 190 insertions(+), 17 deletions(-) diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/corrections/QuickFixProcessor.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/corrections/QuickFixProcessor.java index fb74dd45eb..63966f1f60 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/corrections/QuickFixProcessor.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/corrections/QuickFixProcessor.java @@ -548,8 +548,11 @@ private void process(CodeActionParams params, IInvocationContext context, IProbl case IProblem.SwitchExpressionsYieldMissingEnumConstantCase: LocalCorrectionsSubProcessor.getMissingEnumConstantCaseProposals(context, problem, proposals); break; - case IProblem.MissingDefaultCase: + case IProblem.EnhancedSwitchMissingDefault: case IProblem.SwitchExpressionsYieldMissingDefaultCase: + LocalCorrectionsSubProcessor.addPermittedTypesProposal(context, problem, proposals); + break; + case IProblem.MissingDefaultCase: LocalCorrectionsSubProcessor.addMissingDefaultCaseProposal(context, problem, proposals); break; case IProblem.MissingEnumConstantCaseDespiteDefault: diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/corrections/proposals/LocalCorrectionsSubProcessor.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/corrections/proposals/LocalCorrectionsSubProcessor.java index 29bbf92613..e8b17c008a 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/corrections/proposals/LocalCorrectionsSubProcessor.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/corrections/proposals/LocalCorrectionsSubProcessor.java @@ -103,15 +103,23 @@ import org.eclipse.jdt.internal.corext.util.JavaModelUtil; import org.eclipse.jdt.internal.ui.fix.CodeStyleCleanUpCore; import org.eclipse.jdt.internal.ui.fix.UnnecessaryCodeCleanUpCore; +import org.eclipse.jdt.internal.ui.text.correction.LocalCorrectionsBaseSubProcessor; import org.eclipse.jdt.internal.ui.text.correction.proposals.ChangeMethodSignatureProposalCore; import org.eclipse.jdt.internal.ui.text.correction.proposals.ChangeMethodSignatureProposalCore.ChangeDescription; import org.eclipse.jdt.internal.ui.text.correction.proposals.ChangeMethodSignatureProposalCore.InsertDescription; import org.eclipse.jdt.internal.ui.text.correction.proposals.ChangeMethodSignatureProposalCore.RemoveDescription; import org.eclipse.jdt.internal.ui.text.correction.proposals.ConstructorFromSuperclassProposalCore; +import org.eclipse.jdt.internal.ui.text.correction.proposals.CreateNewObjectProposalCore; +import org.eclipse.jdt.internal.ui.text.correction.proposals.CreateObjectReferenceProposalCore; +import org.eclipse.jdt.internal.ui.text.correction.proposals.CreateVariableReferenceProposalCore; import org.eclipse.jdt.internal.ui.text.correction.proposals.FixCorrectionProposalCore; import org.eclipse.jdt.internal.ui.text.correction.proposals.LinkedCorrectionProposalCore; import org.eclipse.jdt.internal.ui.text.correction.proposals.MissingAnnotationAttributesProposalCore; +import org.eclipse.jdt.internal.ui.text.correction.proposals.ModifierChangeCorrectionProposalCore; +import org.eclipse.jdt.internal.ui.text.correction.proposals.NewMethodCorrectionProposalCore; +import org.eclipse.jdt.internal.ui.text.correction.proposals.NewVariableCorrectionProposalCore; import org.eclipse.jdt.internal.ui.text.correction.proposals.RefactoringCorrectionProposalCore; +import org.eclipse.jdt.internal.ui.text.correction.proposals.ReplaceCorrectionProposalCore; import org.eclipse.jdt.internal.ui.util.ASTHelper; import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin; import org.eclipse.jdt.ls.core.internal.corrections.CorrectionMessages; @@ -126,7 +134,7 @@ import org.eclipse.jdt.ui.text.java.correction.ASTRewriteCorrectionProposalCore; import org.eclipse.lsp4j.CodeActionKind; -public class LocalCorrectionsSubProcessor { +public class LocalCorrectionsSubProcessor extends LocalCorrectionsBaseSubProcessor { private static final String ADD_STATIC_ACCESS_ID = "org.eclipse.jdt.ui.correction.changeToStatic"; //$NON-NLS-1$ @@ -1085,22 +1093,11 @@ public static void getTryWithResourceProposals(IInvocationContext context, IProb } public static void addTypeAsPermittedSubTypeProposal(IInvocationContext context, IProblemLocation problem, Collection proposals) { - SealedClassFixCore fix = SealedClassFixCore.addTypeAsPermittedSubTypeProposal(context.getASTRoot(), problem); - if (fix != null) { - String label = fix.getDisplayString(); - CompilationUnitChange change; - try { - change = fix.createChange(null); + new LocalCorrectionsSubProcessor().getTypeAsPermittedSubTypeProposal(context, problem, proposals); + } - ASTNode selectedNode = problem.getCoveringNode(context.getASTRoot()); - IType sealedType = SealedClassFixCore.getSealedType(selectedNode); - ICompilationUnit unit = SealedClassFixCore.getCompilationUnitForSealedType(sealedType); - CUCorrectionProposalCore proposal = new CUCorrectionProposalCore(label, unit, change, IProposalRelevance.DECLARE_SEALED_AS_DIRECT_SUPER_TYPE); - proposals.add(CodeActionHandler.wrap(proposal, CodeActionKind.QuickFix)); - } catch (CoreException e) { - // do nothing - } - } + public static void addPermittedTypesProposal(IInvocationContext context, IProblemLocation problem, Collection proposals) { + new LocalCorrectionsSubProcessor().getPermittedTypesProposal(context, problem, proposals); } public static void addSealedAsDirectSuperTypeProposal(IInvocationContext context, IProblemLocation problem, Collection proposals) { @@ -1130,4 +1127,131 @@ public static void addValueForAnnotationProposals(IInvocationContext context, IP } } + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.ui.text.correction.LocalCorrectionsBaseSubProcessor#refactoringCorrectionProposalToT(org.eclipse.jdt.internal.ui.text.correction.proposals.RefactoringCorrectionProposalCore, int) + */ + @Override + protected ProposalKindWrapper refactoringCorrectionProposalToT(RefactoringCorrectionProposalCore core, int uid) { + // TODO Auto-generated method stub + return null; + } + + @Override + protected ProposalKindWrapper linkedCorrectionProposalToT(LinkedCorrectionProposalCore core, int uid) { + return CodeActionHandler.wrap(core, CodeActionKind.QuickFix); + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.ui.text.correction.LocalCorrectionsBaseSubProcessor#changeMethodSignatureProposalToT(org.eclipse.jdt.internal.ui.text.correction.proposals.ChangeMethodSignatureProposalCore, int) + */ + @Override + protected ProposalKindWrapper changeMethodSignatureProposalToT(ChangeMethodSignatureProposalCore core, int uid) { + // TODO Auto-generated method stub + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.ui.text.correction.LocalCorrectionsBaseSubProcessor#fixCorrectionProposalToT(org.eclipse.jdt.internal.ui.text.correction.proposals.FixCorrectionProposalCore, int) + */ + @Override + protected ProposalKindWrapper fixCorrectionProposalToT(FixCorrectionProposalCore core, int uid) { + // TODO Auto-generated method stub + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.ui.text.correction.LocalCorrectionsBaseSubProcessor#constructorFromSuperClassProposalToT(org.eclipse.jdt.internal.ui.text.correction.proposals.ConstructorFromSuperclassProposalCore, int) + */ + @Override + protected ProposalKindWrapper constructorFromSuperClassProposalToT(ConstructorFromSuperclassProposalCore core, int uid) { + // TODO Auto-generated method stub + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.ui.text.correction.LocalCorrectionsBaseSubProcessor#createNewObjectProposalToT(org.eclipse.jdt.internal.ui.text.correction.proposals.CreateNewObjectProposalCore, int) + */ + @Override + protected ProposalKindWrapper createNewObjectProposalToT(CreateNewObjectProposalCore core, int uid) { + // TODO Auto-generated method stub + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.ui.text.correction.LocalCorrectionsBaseSubProcessor#createObjectReferenceProposalToT(org.eclipse.jdt.internal.ui.text.correction.proposals.CreateObjectReferenceProposalCore, int) + */ + @Override + protected ProposalKindWrapper createObjectReferenceProposalToT(CreateObjectReferenceProposalCore core, int uid) { + // TODO Auto-generated method stub + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.ui.text.correction.LocalCorrectionsBaseSubProcessor#createVariableReferenceProposalToT(org.eclipse.jdt.internal.ui.text.correction.proposals.CreateVariableReferenceProposalCore, int) + */ + @Override + protected ProposalKindWrapper createVariableReferenceProposalToT(CreateVariableReferenceProposalCore core, int uid) { + // TODO Auto-generated method stub + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.ui.text.correction.LocalCorrectionsBaseSubProcessor#astRewriteCorrectionProposalToT(org.eclipse.jdt.ui.text.java.correction.ASTRewriteCorrectionProposalCore, int) + */ + @Override + protected ProposalKindWrapper astRewriteCorrectionProposalToT(ASTRewriteCorrectionProposalCore core, int uid) { + // TODO Auto-generated method stub + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.ui.text.correction.LocalCorrectionsBaseSubProcessor#replaceCorrectionProposalToT(org.eclipse.jdt.internal.ui.text.correction.proposals.ReplaceCorrectionProposalCore, int) + */ + @Override + protected ProposalKindWrapper replaceCorrectionProposalToT(ReplaceCorrectionProposalCore core, int uid) { + // TODO Auto-generated method stub + return null; + } + + @Override + protected ProposalKindWrapper cuCorrectionProposalToT(CUCorrectionProposalCore core, int uid) { + return CodeActionHandler.wrap(core, CodeActionKind.QuickFix); + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.ui.text.correction.LocalCorrectionsBaseSubProcessor#newVariableCorrectionProposalToT(org.eclipse.jdt.internal.ui.text.correction.proposals.NewVariableCorrectionProposalCore, int) + */ + @Override + protected ProposalKindWrapper newVariableCorrectionProposalToT(NewVariableCorrectionProposalCore core, int uid) { + // TODO Auto-generated method stub + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.ui.text.correction.LocalCorrectionsBaseSubProcessor#missingAnnotationAttributesProposalToT(org.eclipse.jdt.internal.ui.text.correction.proposals.MissingAnnotationAttributesProposalCore, int) + */ + @Override + protected ProposalKindWrapper missingAnnotationAttributesProposalToT(MissingAnnotationAttributesProposalCore core, int uid) { + // TODO Auto-generated method stub + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.ui.text.correction.LocalCorrectionsBaseSubProcessor#newMethodCorrectionProposalToT(org.eclipse.jdt.internal.ui.text.correction.proposals.NewMethodCorrectionProposalCore, int) + */ + @Override + protected ProposalKindWrapper newMethodCorrectionProposalToT(NewMethodCorrectionProposalCore core, int uid) { + // TODO Auto-generated method stub + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.ui.text.correction.LocalCorrectionsBaseSubProcessor#modifierChangeCorrectionProposalToT(org.eclipse.jdt.internal.ui.text.correction.proposals.ModifierChangeCorrectionProposalCore, int) + */ + @Override + protected ProposalKindWrapper modifierChangeCorrectionProposalToT(ModifierChangeCorrectionProposalCore core, int uid) { + // TODO Auto-generated method stub + return null; + } + } diff --git a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/correction/ModifierCorrectionsQuickFixTest.java b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/correction/ModifierCorrectionsQuickFixTest.java index 4119222e6d..46ea39ceb2 100644 --- a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/correction/ModifierCorrectionsQuickFixTest.java +++ b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/correction/ModifierCorrectionsQuickFixTest.java @@ -1305,4 +1305,50 @@ public void testAddPermitsToDirectSuperClass() throws Exception { assertCodeActions(cu, e1); } + @Test + public void testAddPermittedSubTypeForSwitch() throws Exception { + Map options21 = new HashMap<>(); + JavaModelUtil.setComplianceOptions(options21, JavaCore.VERSION_21); + fJProject.setOptions(options21); + IPackageFragment pack1 = fSourceFolder.createPackageFragment("test", false, null); + assertNoErrors(fJProject.getResource()); + + StringBuilder buf = new StringBuilder(); + buf = new StringBuilder(); + buf.append("package test;\n" + + "public class SealedInSwitch {\n" + + " public static void test() {\n" + + " Shape input = null;\n" + + " switch (input) {\n" + + " }\n" + + " }\n" + + " public sealed class Shape permits Oval, Triangle, Rectangle {}\n" + + " public final class Oval extends Shape {}\n" + + " public final class Triangle extends Shape {}\n" + + " public final class Rectangle extends Shape {}" + + "}\n"); + ICompilationUnit cu = pack1.createCompilationUnit("SealedInSwitch.java", buf.toString(), false, null); + + buf = new StringBuilder(); + buf.append("package test;\n" + + "public class SealedInSwitch {\n" + + " public static void test() {\n" + + " Shape input = null;\n" + + " switch (input) {\n" + + " case SealedInSwitch.Oval s -> {}\n" + + " case SealedInSwitch.Triangle s2 -> {}\n" + + " case SealedInSwitch.Rectangle s3 -> {}\n" + + " case null -> {}\n" + + " default -> {}\n" + + " }\n" + + " }\n" + + " public sealed class Shape permits Oval, Triangle, Rectangle {}\n" + + " public final class Oval extends Shape {}\n" + + " public final class Triangle extends Shape {}\n" + + " public final class Rectangle extends Shape {}" + + "}\n"); + Expected e1 = new Expected("Add permitted type cases", buf.toString()); + assertCodeActions(cu, e1); + } + }