diff --git a/java/java-impl/src/META-INF/JavaPlugin.xml b/java/java-impl/src/META-INF/JavaPlugin.xml index bf5413595e25..b8376e9e36c6 100644 --- a/java/java-impl/src/META-INF/JavaPlugin.xml +++ b/java/java-impl/src/META-INF/JavaPlugin.xml @@ -1875,6 +1875,10 @@ com.intellij.codeInsight.intention.impl.CreateFieldFromParameterAction Java/Declaration + + com.intellij.codeInsight.intention.impl.MakeSealedAction + Java/Declaration + com.intellij.codeInsight.intention.impl.UnwrapElseBranchAction Java/Control Flow diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/MakeSealedAction.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/MakeSealedAction.java new file mode 100644 index 000000000000..1b8769fbc749 --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/MakeSealedAction.java @@ -0,0 +1,167 @@ +// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.codeInsight.intention.impl; + +import com.intellij.codeInsight.FileModificationService; +import com.intellij.codeInsight.daemon.impl.analysis.HighlightingFeature; +import com.intellij.codeInsight.intention.BaseElementAtCaretIntentionAction; +import com.intellij.codeInspection.util.IntentionName; +import com.intellij.java.JavaBundle; +import com.intellij.lang.java.JavaLanguage; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.psi.search.searches.ClassInheritorsSearch; +import com.intellij.psi.search.searches.FunctionalExpressionSearch; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.refactoring.util.CommonRefactoringUtil; +import com.intellij.util.IncorrectOperationException; +import com.intellij.util.SequentialModalProgressTask; +import com.intellij.util.SequentialTask; +import one.util.streamex.StreamEx; +import org.jetbrains.annotations.NotNull; + +import java.util.Arrays; +import java.util.Objects; +import java.util.stream.Stream; + +public class MakeSealedAction extends BaseElementAtCaretIntentionAction { + @Override + @NotNull + public String getFamilyName() { + return JavaBundle.message("intention.family.name.make.sealed"); + } + + @Override + public @IntentionName @NotNull String getText() { + return JavaBundle.message("intention.name.make.sealed"); + } + + @Override + public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) { + PsiClass aClass = PsiTreeUtil.getParentOfType(element, PsiClass.class); + if (aClass == null) return false; + return isAvailable(aClass, editor); + } + + private static boolean isAvailable(@NotNull PsiClass aClass, Editor editor) { + if (!HighlightingFeature.SEALED_CLASSES.isAvailable(aClass)) return false; + int offset = editor.getCaretModel().getOffset(); + PsiElement lBrace = aClass.getLBrace(); + if (lBrace == null) return false; + if (offset >= lBrace.getTextRange().getStartOffset()) return false; + if (aClass.hasModifierProperty(PsiModifier.SEALED)) return false; + if (aClass.getImplementsList() == null) return false; + if (aClass.getPermitsList() != null) return false; + if (aClass.getModifierList() == null) return false; + if (aClass.hasModifierProperty(PsiModifier.FINAL)) return false; + return !aClass.hasAnnotation(CommonClassNames.JAVA_LANG_FUNCTIONAL_INTERFACE); + } + + @Override + public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element) throws IncorrectOperationException { + PsiClass aClass = PsiTreeUtil.getParentOfType(element, PsiClass.class); + if (aClass == null) return; + if (!isAvailable(aClass, editor)) return; + FileModificationService.getInstance().prepareFileForWrite(aClass.getContainingFile()); + if (aClass.isInterface()) { + if (FunctionalExpressionSearch.search(aClass).findFirst() != null) { + String message = JavaBundle.message("intention.error.make.sealed.class.is.used.in.functional.expression"); + CommonRefactoringUtil.showErrorHint(project, editor, message, getErrorTitle(), null); + return; + } + } + + PsiClass[] inheritors = ClassInheritorsSearch.search(aClass, false).toArray(PsiClass.EMPTY_ARRAY); + String[] names = Stream.of(inheritors) + .map(aClass1 -> aClass1.getQualifiedName()) + .toArray(String[]::new); + String[] nonNullNames = StreamEx.of(names).nonNull().toArray(String[]::new); + if (nonNullNames.length != names.length) { + String message = JavaBundle.message("intention.error.make.sealed.class.has.anonymous.inheritors"); + CommonRefactoringUtil.showErrorHint(project, editor, message, getErrorTitle(), null); + return; + } + setParentModifier(aClass); + if (nonNullNames.length != 0) { + if (shouldCreatePermitsList(inheritors, aClass.getContainingFile())) { + addPermitsClause(project, aClass, nonNullNames); + } + setInheritorsModifiers(project, inheritors); + } + } + + public boolean shouldCreatePermitsList(PsiClass[] inheritors, PsiFile parentFile) { + return !Arrays.stream(inheritors).allMatch(psiClass -> psiClass.getContainingFile() == parentFile); + } + + public void setParentModifier(PsiClass aClass) { + ApplicationManager.getApplication().runWriteAction(() -> { + PsiModifierList modifierList = Objects.requireNonNull(aClass.getModifierList()); + if (modifierList.hasModifierProperty(PsiModifier.NON_SEALED)) { + modifierList.setModifierProperty(PsiModifier.NON_SEALED, false); + } + modifierList.setModifierProperty(PsiModifier.SEALED, true); + }); + } + + public void setInheritorsModifiers(@NotNull Project project, PsiClass[] inheritors) { + String title = JavaBundle.message("intention.error.make.sealed.class.task.title.set.inheritors.modifiers"); + SequentialModalProgressTask task = new SequentialModalProgressTask(project, title, true); + task.setTask(new SequentialTask() { + private int current = 0; + private final int size = inheritors.length; + + @Override + public boolean isDone() { + return current >= size; + } + + @Override + public boolean iteration() { + task.getIndicator().setFraction(((double)current) / size); + PsiClass inheritor = inheritors[current]; + current++; + PsiModifierList modifierList = inheritor.getModifierList(); + assert modifierList != null; // ensured by absence of anonymous classes + if (modifierList.hasModifierProperty(PsiModifier.SEALED) || + modifierList.hasModifierProperty(PsiModifier.NON_SEALED) || + modifierList.hasModifierProperty(PsiModifier.FINAL)) { + return isDone(); + } + ApplicationManager.getApplication().runWriteAction(() -> { + modifierList.setModifierProperty(PsiModifier.NON_SEALED, true); + }); + return isDone(); + } + }); + ProgressManager.getInstance().run(task); + } + + public static void addPermitsClause(@NotNull Project project, PsiClass aClass, String[] nonNullNames) { + String permitsClause = StreamEx.of(nonNullNames).sorted().joining(",", "permits ", ""); + PsiReferenceList permitsList = createPermitsClause(project, permitsClause); + PsiReferenceList implementsList = Objects.requireNonNull(aClass.getImplementsList()); + ApplicationManager.getApplication().runWriteAction(() -> { + aClass.addAfter(permitsList, implementsList); + }); + } + + @NotNull + private static PsiReferenceList createPermitsClause(@NotNull Project project, String permitsClause) { + PsiFileFactory factory = PsiFileFactory.getInstance(project); + PsiJavaFile javaFile = (PsiJavaFile)factory.createFileFromText(JavaLanguage.INSTANCE, "class __Dummy " + permitsClause + "{}"); + PsiClass newClass = javaFile.getClasses()[0]; + return Objects.requireNonNull(newClass.getPermitsList()); + } + + @Override + public boolean startInWriteAction() { + return false; + } + + private static String getErrorTitle() { + return JavaBundle.message("intention.error.make.sealed.class.hint.title"); + } +} diff --git a/java/java-impl/src/intentionDescriptions/MakeSealedAction/after.java.template b/java/java-impl/src/intentionDescriptions/MakeSealedAction/after.java.template new file mode 100644 index 000000000000..f9a38dc3468b --- /dev/null +++ b/java/java-impl/src/intentionDescriptions/MakeSealedAction/after.java.template @@ -0,0 +1,6 @@ +sealed class Main { } + +non-sealed class Direct1 extends Main {} +sealed class Direct2 extends Main {} + +class NonDirect extends Direct1 {} \ No newline at end of file diff --git a/java/java-impl/src/intentionDescriptions/MakeSealedAction/before.java.template b/java/java-impl/src/intentionDescriptions/MakeSealedAction/before.java.template new file mode 100644 index 000000000000..7dca161aa3f7 --- /dev/null +++ b/java/java-impl/src/intentionDescriptions/MakeSealedAction/before.java.template @@ -0,0 +1,6 @@ +class Main { } + +class Direct1 extends Main {} +sealed class Direct2 extends Main {} + +class NonDirect extends Direct1 {} \ No newline at end of file diff --git a/java/java-impl/src/intentionDescriptions/MakeSealedAction/description.html b/java/java-impl/src/intentionDescriptions/MakeSealedAction/description.html new file mode 100644 index 000000000000..c3e798f3ca50 --- /dev/null +++ b/java/java-impl/src/intentionDescriptions/MakeSealedAction/description.html @@ -0,0 +1,6 @@ + + +This intention makes the class sealed, lists all direct inheritors in permits clause if inheritors are not in the same file and +adds 'non-sealed' modifier if none of 'sealed'/'non-sealed' modifiers were not specified for inheritors. + + \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/makeClassSealed/afterInheritorsWithModifiers.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/makeClassSealed/afterInheritorsWithModifiers.java new file mode 100644 index 000000000000..0b794b953e3a --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/makeClassSealed/afterInheritorsWithModifiers.java @@ -0,0 +1,10 @@ +// "Make sealed" "true" + +public sealed class Main { } + +sealed class Direct1 extends Main {} +non-sealed class Direct2 extends Main {} +final class Direct3 extends Main {} +non-sealed class Direct4 extends Main {} + +class NonDirect extends Direct1 {} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/makeClassSealed/afterNoInheritors.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/makeClassSealed/afterNoInheritors.java new file mode 100644 index 000000000000..4a9be07c5aab --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/makeClassSealed/afterNoInheritors.java @@ -0,0 +1,3 @@ +// "Make sealed" "true" + +public sealed class Main { } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/makeClassSealed/afterNonDirect.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/makeClassSealed/afterNonDirect.java new file mode 100644 index 000000000000..93465f4ffdb0 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/makeClassSealed/afterNonDirect.java @@ -0,0 +1,8 @@ +// "Make sealed" "true" + +public sealed class Main { } + +non-sealed class Direct1 extends Main {} +non-sealed class Direct2 extends Main {} + +class NonDirect extends Direct1 {} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/makeClassSealed/afterNonSealed.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/makeClassSealed/afterNonSealed.java new file mode 100644 index 000000000000..aa5258bfb343 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/makeClassSealed/afterNonSealed.java @@ -0,0 +1,5 @@ +// "Make sealed" "true" + +public sealed class Main { } + +non-sealed class Direct extends Main {} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/makeClassSealed/beforeFinal.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/makeClassSealed/beforeFinal.java new file mode 100644 index 000000000000..2a74320db162 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/makeClassSealed/beforeFinal.java @@ -0,0 +1,5 @@ +// "Make sealed" "false" + +public final class Main { } + +class Direct extends Main {} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/makeClassSealed/beforeInheritorsWithModifiers.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/makeClassSealed/beforeInheritorsWithModifiers.java new file mode 100644 index 000000000000..4e0303966a37 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/makeClassSealed/beforeInheritorsWithModifiers.java @@ -0,0 +1,10 @@ +// "Make sealed" "true" + +public class Main { } + +sealed class Direct1 extends Main {} +non-sealed class Direct2 extends Main {} +final class Direct3 extends Main {} +class Direct4 extends Main {} + +class NonDirect extends Direct1 {} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/makeClassSealed/beforeNoInheritors.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/makeClassSealed/beforeNoInheritors.java new file mode 100644 index 000000000000..ce5021da8faa --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/makeClassSealed/beforeNoInheritors.java @@ -0,0 +1,3 @@ +// "Make sealed" "true" + +public class Main { } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/makeClassSealed/beforeNonDirect.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/makeClassSealed/beforeNonDirect.java new file mode 100644 index 000000000000..28d79a24fa6e --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/makeClassSealed/beforeNonDirect.java @@ -0,0 +1,8 @@ +// "Make sealed" "true" + +public class Main { } + +class Direct1 extends Main {} +class Direct2 extends Main {} + +class NonDirect extends Direct1 {} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/makeClassSealed/beforeNonSealed.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/makeClassSealed/beforeNonSealed.java new file mode 100644 index 000000000000..97789fa96670 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/makeClassSealed/beforeNonSealed.java @@ -0,0 +1,5 @@ +// "Make sealed" "true" + +public non-sealed class Main { } + +class Direct extends Main {} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/makeClassSealed/beforeSealed.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/makeClassSealed/beforeSealed.java new file mode 100644 index 000000000000..9b0ba32bbd14 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/makeClassSealed/beforeSealed.java @@ -0,0 +1,5 @@ +// "Make sealed" "false" + +public sealed class Main { } + +class Direct extends Main {} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/makeClassSealed/failing/AnonymousClass.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/makeClassSealed/failing/AnonymousClass.java new file mode 100644 index 000000000000..d6f5102619bc --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/makeClassSealed/failing/AnonymousClass.java @@ -0,0 +1,21 @@ +interface Functional { + void run(); +} + +class Inheritor implements Functional { + @Override + public void run() { + + } +} + +class A { + void foo() { + Functional f = new Functional() { + @Override + public void run() { + + } + }; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/makeClassSealed/failing/FunctionalInterface.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/makeClassSealed/failing/FunctionalInterface.java new file mode 100644 index 000000000000..c187dc8c9984 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/makeClassSealed/failing/FunctionalInterface.java @@ -0,0 +1,9 @@ +interface Functional { + void run(); +} + +class A { + void foo() { + Functional f = () -> {}; + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/intention/MakeSealedActionFailingTest.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/intention/MakeSealedActionFailingTest.java new file mode 100644 index 000000000000..65253d5bd716 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/intention/MakeSealedActionFailingTest.java @@ -0,0 +1,53 @@ +/* + * Copyright 2000-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.java.codeInsight.intention; + +import com.intellij.codeInsight.intention.impl.MakeSealedAction; +import com.intellij.java.JavaBundle; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.refactoring.util.CommonRefactoringUtil; +import com.intellij.testFramework.LightJavaCodeInsightTestCase; +import com.intellij.testFramework.LightProjectDescriptor; +import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase; +import org.jetbrains.annotations.NotNull; + +public class MakeSealedActionFailingTest extends LightJavaCodeInsightTestCase { + @Override + protected @NotNull LightProjectDescriptor getProjectDescriptor() { + return LightJavaCodeInsightFixtureTestCase.JAVA_15; + } + + public void testFunctionalInterface() { + checkErrorMessage(JavaBundle.message("intention.error.make.sealed.class.is.used.in.functional.expression")); + } + + public void testAnonymousClass() { + checkErrorMessage(JavaBundle.message("intention.error.make.sealed.class.has.anonymous.inheritors")); + } + + private void checkErrorMessage(@NotNull String message) { + configureByFile("/codeInsight/daemonCodeAnalyzer/quickFix/makeClassSealed/failing/" + getTestName(false) + ".java"); + MakeSealedAction action = new MakeSealedAction(); + assertTrue(action.isAvailable(getProject(), getEditor(), getFile())); + try { + ApplicationManager.getApplication().runWriteAction(() -> action.invoke(getProject(), getEditor(), getFile())); + } catch (CommonRefactoringUtil.RefactoringErrorHintException e) { + assertEquals(message, e.getMessage()); + return; + } + fail("Test must fail with error message"); + } +} diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/intention/MakeSealedActionMultiFileTest.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/intention/MakeSealedActionMultiFileTest.java new file mode 100644 index 000000000000..499b6069c214 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/intention/MakeSealedActionMultiFileTest.java @@ -0,0 +1,48 @@ +/* + * Copyright 2000-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.java.codeInsight.intention; + +import com.intellij.codeInsight.intention.impl.MakeSealedAction; +import com.intellij.openapi.command.WriteCommandAction; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiFile; +import com.intellij.testFramework.LightProjectDescriptor; +import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase; +import org.jetbrains.annotations.NotNull; + +public class MakeSealedActionMultiFileTest extends LightJavaCodeInsightFixtureTestCase { + @Override + protected @NotNull LightProjectDescriptor getProjectDescriptor() { + return LightJavaCodeInsightFixtureTestCase.JAVA_15; + } + + public void testMultiFile() { + PsiFile main = myFixture.configureByText("Main.java", "class Main {}"); + PsiClass direct1 = myFixture.addClass("class Direct1 extends Main {}"); + PsiClass direct2 = myFixture.addClass("class Direct2 extends Main {}"); + PsiClass indirect = myFixture.addClass("class Indirect extends Direct1 {}"); + + MakeSealedAction action = new MakeSealedAction(); + assertTrue(action.isAvailable(getProject(), getEditor(), getFile())); + WriteCommandAction.runWriteCommandAction(getProject(), () -> { + action.invoke(getProject(), getEditor(), getFile()); + }); + assertEquals("sealed class Main permits Direct1, Direct2 {}", main.getText()); + assertEquals("non-sealed class Direct1 extends Main {}", direct1.getText()); + assertEquals("non-sealed class Direct2 extends Main {}", direct2.getText()); + assertEquals("class Indirect extends Direct1 {}", indirect.getText()); + } +} diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/intention/MakeSealedActionTest.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/intention/MakeSealedActionTest.java new file mode 100644 index 000000000000..6a53e1c9f508 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/intention/MakeSealedActionTest.java @@ -0,0 +1,33 @@ +/* + * Copyright 2000-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.java.codeInsight.intention; + +import com.intellij.codeInsight.daemon.LightIntentionActionTestCase; +import com.intellij.testFramework.LightProjectDescriptor; +import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase; +import org.jetbrains.annotations.NotNull; + +public class MakeSealedActionTest extends LightIntentionActionTestCase { + @Override + protected @NotNull LightProjectDescriptor getProjectDescriptor() { + return LightJavaCodeInsightFixtureTestCase.JAVA_15; + } + + @Override + protected String getBasePath() { + return "/codeInsight/daemonCodeAnalyzer/quickFix/makeClassSealed"; + } +} diff --git a/java/openapi/resources/messages/JavaBundle.properties b/java/openapi/resources/messages/JavaBundle.properties index d8cdc1468192..f2b06b5372e7 100644 --- a/java/openapi/resources/messages/JavaBundle.properties +++ b/java/openapi/resources/messages/JavaBundle.properties @@ -1259,4 +1259,10 @@ slice.usage.message.in.file.stopped.here=(in {0} file - stopped here) slice.usage.message.tracking.container.contents=(Tracking container ''{0}{1}'' contents) slice.usage.message.location=in {0} intention.name.move.into.if.branches=Move up into 'if' statement branches -intention.name.collapse.into.loop=Collapse into loop \ No newline at end of file +intention.name.collapse.into.loop=Collapse into loop +intention.family.name.make.sealed=Make class sealed +intention.name.make.sealed=Make sealed +intention.error.make.sealed.class.is.used.in.functional.expression=Class is used in functional expression +intention.error.make.sealed.class.hint.title=Make Sealed +intention.error.make.sealed.class.has.anonymous.inheritors=Some of the inheritors are anonymous +intention.error.make.sealed.class.task.title.set.inheritors.modifiers=Setting inheritors modifiers \ No newline at end of file