diff --git a/idea/resources/META-INF/plugin-common.xml b/idea/resources/META-INF/plugin-common.xml
index 60f2a0a5324..4cc19631437 100644
--- a/idea/resources/META-INF/plugin-common.xml
+++ b/idea/resources/META-INF/plugin-common.xml
@@ -1644,6 +1644,11 @@
Kotlin
+
+ org.jetbrains.kotlin.idea.intentions.AddMissingClassKeywordIntention
+ Kotlin
+
+
class E
\ No newline at end of file
diff --git a/idea/resources/intentionDescriptions/AddMissingClassKeywordIntention/before.kt.template b/idea/resources/intentionDescriptions/AddMissingClassKeywordIntention/before.kt.template
new file mode 100644
index 00000000000..f593bae5de2
--- /dev/null
+++ b/idea/resources/intentionDescriptions/AddMissingClassKeywordIntention/before.kt.template
@@ -0,0 +1 @@
+enum E
\ No newline at end of file
diff --git a/idea/resources/intentionDescriptions/AddMissingClassKeywordIntention/description.html b/idea/resources/intentionDescriptions/AddMissingClassKeywordIntention/description.html
new file mode 100644
index 00000000000..0dbef2ce12a
--- /dev/null
+++ b/idea/resources/intentionDescriptions/AddMissingClassKeywordIntention/description.html
@@ -0,0 +1,5 @@
+
+
+This intention adds a missing class keyword.
+
+
diff --git a/idea/resources/messages/KotlinBundle.properties b/idea/resources/messages/KotlinBundle.properties
index 871c9431ff6..a96693bb826 100644
--- a/idea/resources/messages/KotlinBundle.properties
+++ b/idea/resources/messages/KotlinBundle.properties
@@ -2195,5 +2195,5 @@ move.refactoring.error.text.cannot.perform.refactoring.since.the.following.files
kotlin.script.definitions.model.name.is.enabled=Is Enabled
kotlin.script.definitions.model.name.pattern.extension=Pattern/Extension
kotlin.script.definitions.model.name.name=Name
-codestyle.name.kotlin=Kotlin
+add.missing.class.keyword=Add missing 'class' keyword
fix.move.typealias.to.top.level=Move typealias to top level
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/AddMissingClassKeywordIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/AddMissingClassKeywordIntention.kt
new file mode 100644
index 00000000000..3d642613238
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/intentions/AddMissingClassKeywordIntention.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.intentions
+
+import com.intellij.openapi.editor.Editor
+import com.intellij.psi.PsiDocumentManager
+import com.intellij.psi.PsiElement
+import com.intellij.psi.PsiErrorElement
+import org.jetbrains.kotlin.idea.KotlinBundle
+import org.jetbrains.kotlin.lexer.KtTokens
+import org.jetbrains.kotlin.psi.KtClass
+import org.jetbrains.kotlin.psi.KtModifierList
+import org.jetbrains.kotlin.psi.psiUtil.getPrevSiblingIgnoringWhitespaceAndComments
+import org.jetbrains.kotlin.psi.psiUtil.startOffset
+
+class AddMissingClassKeywordIntention : SelfTargetingIntention(
+ PsiElement::class.java,
+ KotlinBundle.message("add.missing.class.keyword")
+) {
+ companion object {
+ private val targetKeywords = listOf(
+ KtTokens.ANNOTATION_KEYWORD,
+ KtTokens.DATA_KEYWORD,
+ KtTokens.SEALED_KEYWORD,
+ KtTokens.INNER_KEYWORD
+ )
+ }
+
+ override fun isApplicableTo(element: PsiElement, caretOffset: Int): Boolean {
+ if (element.node?.elementType != KtTokens.IDENTIFIER) return false
+ val ktClass = element.parent as? KtClass
+ if (ktClass == null) {
+ val errorElement = element.parent as? PsiErrorElement ?: return false
+ val modifierList = errorElement.getPrevSiblingIgnoringWhitespaceAndComments() as? KtModifierList ?: return false
+ return targetKeywords.any { modifierList.hasModifier(it) }
+ } else {
+ return ktClass.isEnum() && ktClass.getClassKeyword() == null
+ }
+ }
+
+ override fun applyTo(element: PsiElement, editor: Editor?) {
+ val document = editor?.document ?: return
+ val targetElement = (element.parent as? PsiErrorElement) ?: element
+ document.insertString(targetElement.startOffset, "class ")
+ PsiDocumentManager.getInstance(element.project).commitDocument(document)
+ }
+}
diff --git a/idea/testData/intentions/addMissingClassKeyword/.intention b/idea/testData/intentions/addMissingClassKeyword/.intention
new file mode 100644
index 00000000000..12fde8d657f
--- /dev/null
+++ b/idea/testData/intentions/addMissingClassKeyword/.intention
@@ -0,0 +1 @@
+org.jetbrains.kotlin.idea.intentions.AddMissingClassKeywordIntention
diff --git a/idea/testData/intentions/addMissingClassKeyword/abstract.kt b/idea/testData/intentions/addMissingClassKeyword/abstract.kt
new file mode 100644
index 00000000000..4a32fdc5736
--- /dev/null
+++ b/idea/testData/intentions/addMissingClassKeyword/abstract.kt
@@ -0,0 +1,5 @@
+// IS_APPLICABLE: false
+// DISABLE-ERRORS
+abstract Foo {
+ abstract fun foo()
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/addMissingClassKeyword/annottion.kt b/idea/testData/intentions/addMissingClassKeyword/annottion.kt
new file mode 100644
index 00000000000..1534add0f45
--- /dev/null
+++ b/idea/testData/intentions/addMissingClassKeyword/annottion.kt
@@ -0,0 +1 @@
+annotation Foo
\ No newline at end of file
diff --git a/idea/testData/intentions/addMissingClassKeyword/annottion.kt.after b/idea/testData/intentions/addMissingClassKeyword/annottion.kt.after
new file mode 100644
index 00000000000..2e437ae4690
--- /dev/null
+++ b/idea/testData/intentions/addMissingClassKeyword/annottion.kt.after
@@ -0,0 +1 @@
+annotation class Foo
\ No newline at end of file
diff --git a/idea/testData/intentions/addMissingClassKeyword/data.kt b/idea/testData/intentions/addMissingClassKeyword/data.kt
new file mode 100644
index 00000000000..9533eec96f2
--- /dev/null
+++ b/idea/testData/intentions/addMissingClassKeyword/data.kt
@@ -0,0 +1,7 @@
+// DISABLE-ERRORS
+annotation class Ann
+
+@Ann
+private data Foo(val s: String) {
+ fun foo() {}
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/addMissingClassKeyword/data.kt.after b/idea/testData/intentions/addMissingClassKeyword/data.kt.after
new file mode 100644
index 00000000000..cf3c351c97c
--- /dev/null
+++ b/idea/testData/intentions/addMissingClassKeyword/data.kt.after
@@ -0,0 +1,7 @@
+// DISABLE-ERRORS
+annotation class Ann
+
+@Ann
+private data class Foo(val s: String) {
+ fun foo() {}
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/addMissingClassKeyword/dataHasClassKeyword.kt b/idea/testData/intentions/addMissingClassKeyword/dataHasClassKeyword.kt
new file mode 100644
index 00000000000..8447343aba4
--- /dev/null
+++ b/idea/testData/intentions/addMissingClassKeyword/dataHasClassKeyword.kt
@@ -0,0 +1,2 @@
+// IS_APPLICABLE: false
+private data class Foo(val s: String)
\ No newline at end of file
diff --git a/idea/testData/intentions/addMissingClassKeyword/enum.kt b/idea/testData/intentions/addMissingClassKeyword/enum.kt
new file mode 100644
index 00000000000..2868149bdd3
--- /dev/null
+++ b/idea/testData/intentions/addMissingClassKeyword/enum.kt
@@ -0,0 +1,3 @@
+enum Foo(val s: String) {
+ A("a"), B("b")
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/addMissingClassKeyword/enum.kt.after b/idea/testData/intentions/addMissingClassKeyword/enum.kt.after
new file mode 100644
index 00000000000..e689ade0ad5
--- /dev/null
+++ b/idea/testData/intentions/addMissingClassKeyword/enum.kt.after
@@ -0,0 +1,3 @@
+enum class Foo(val s: String) {
+ A("a"), B("b")
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/addMissingClassKeyword/enumHasClassKeyword.kt b/idea/testData/intentions/addMissingClassKeyword/enumHasClassKeyword.kt
new file mode 100644
index 00000000000..64198a38a7c
--- /dev/null
+++ b/idea/testData/intentions/addMissingClassKeyword/enumHasClassKeyword.kt
@@ -0,0 +1,4 @@
+// IS_APPLICABLE: false
+enum class Foo(val s: String) {
+ A("a"), B("b")
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/addMissingClassKeyword/inner.kt b/idea/testData/intentions/addMissingClassKeyword/inner.kt
new file mode 100644
index 00000000000..8a806a93b4a
--- /dev/null
+++ b/idea/testData/intentions/addMissingClassKeyword/inner.kt
@@ -0,0 +1,3 @@
+class C {
+ inner Foo
+}
diff --git a/idea/testData/intentions/addMissingClassKeyword/inner.kt.after b/idea/testData/intentions/addMissingClassKeyword/inner.kt.after
new file mode 100644
index 00000000000..abbc07f69bb
--- /dev/null
+++ b/idea/testData/intentions/addMissingClassKeyword/inner.kt.after
@@ -0,0 +1,3 @@
+class C {
+ inner class Foo
+}
diff --git a/idea/testData/intentions/addMissingClassKeyword/sealed.kt b/idea/testData/intentions/addMissingClassKeyword/sealed.kt
new file mode 100644
index 00000000000..d0dfb094e22
--- /dev/null
+++ b/idea/testData/intentions/addMissingClassKeyword/sealed.kt
@@ -0,0 +1,4 @@
+// DISABLE-ERRORS
+sealed Foo {
+ abstract fun foo()
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/addMissingClassKeyword/sealed.kt.after b/idea/testData/intentions/addMissingClassKeyword/sealed.kt.after
new file mode 100644
index 00000000000..0fe8c7341a8
--- /dev/null
+++ b/idea/testData/intentions/addMissingClassKeyword/sealed.kt.after
@@ -0,0 +1,4 @@
+// DISABLE-ERRORS
+sealed class Foo {
+ abstract fun foo()
+}
\ No newline at end of file
diff --git a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java
index 5671edd2a65..b421e904d64 100644
--- a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java
+++ b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java
@@ -1130,6 +1130,59 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
}
}
+ @TestMetadata("idea/testData/intentions/addMissingClassKeyword")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class AddMissingClassKeyword extends AbstractIntentionTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
+ }
+
+ @TestMetadata("abstract.kt")
+ public void testAbstract() throws Exception {
+ runTest("idea/testData/intentions/addMissingClassKeyword/abstract.kt");
+ }
+
+ public void testAllFilesPresentInAddMissingClassKeyword() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/intentions/addMissingClassKeyword"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), true);
+ }
+
+ @TestMetadata("annottion.kt")
+ public void testAnnottion() throws Exception {
+ runTest("idea/testData/intentions/addMissingClassKeyword/annottion.kt");
+ }
+
+ @TestMetadata("data.kt")
+ public void testData() throws Exception {
+ runTest("idea/testData/intentions/addMissingClassKeyword/data.kt");
+ }
+
+ @TestMetadata("dataHasClassKeyword.kt")
+ public void testDataHasClassKeyword() throws Exception {
+ runTest("idea/testData/intentions/addMissingClassKeyword/dataHasClassKeyword.kt");
+ }
+
+ @TestMetadata("enum.kt")
+ public void testEnum() throws Exception {
+ runTest("idea/testData/intentions/addMissingClassKeyword/enum.kt");
+ }
+
+ @TestMetadata("enumHasClassKeyword.kt")
+ public void testEnumHasClassKeyword() throws Exception {
+ runTest("idea/testData/intentions/addMissingClassKeyword/enumHasClassKeyword.kt");
+ }
+
+ @TestMetadata("inner.kt")
+ public void testInner() throws Exception {
+ runTest("idea/testData/intentions/addMissingClassKeyword/inner.kt");
+ }
+
+ @TestMetadata("sealed.kt")
+ public void testSealed() throws Exception {
+ runTest("idea/testData/intentions/addMissingClassKeyword/sealed.kt");
+ }
+ }
+
@TestMetadata("idea/testData/intentions/addMissingDestructuring")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)