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