diff --git a/idea/resources/intentionDescriptions/AddOpenModifierIntention/after.kt.template b/idea/resources/intentionDescriptions/AddOpenModifierIntention/after.kt.template
new file mode 100644
index 00000000000..792cf5ae192
--- /dev/null
+++ b/idea/resources/intentionDescriptions/AddOpenModifierIntention/after.kt.template
@@ -0,0 +1,5 @@
+open class Foo {
+ open fun foo() {
+
+ }
+}
\ No newline at end of file
diff --git a/idea/resources/intentionDescriptions/AddOpenModifierIntention/before.kt.template b/idea/resources/intentionDescriptions/AddOpenModifierIntention/before.kt.template
new file mode 100644
index 00000000000..82d80c75ea8
--- /dev/null
+++ b/idea/resources/intentionDescriptions/AddOpenModifierIntention/before.kt.template
@@ -0,0 +1,5 @@
+open class Foo {
+ fun foo() {
+
+ }
+}
\ No newline at end of file
diff --git a/idea/resources/intentionDescriptions/AddOpenModifierIntention/description.html b/idea/resources/intentionDescriptions/AddOpenModifierIntention/description.html
new file mode 100644
index 00000000000..1d2481e459d
--- /dev/null
+++ b/idea/resources/intentionDescriptions/AddOpenModifierIntention/description.html
@@ -0,0 +1,5 @@
+
+
+This intention adds an open modifier.
+
+
\ No newline at end of file
diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml
index 26e26508ba8..ff27082c99a 100644
--- a/idea/src/META-INF/plugin.xml
+++ b/idea/src/META-INF/plugin.xml
@@ -1549,6 +1549,11 @@
Kotlin
+
+ org.jetbrains.kotlin.idea.intentions.AddOpenModifierIntention
+ Kotlin
+
+
(
+ KtCallableDeclaration::class.java, "Make open"
+), LowPriorityAction {
+
+ override fun isApplicableTo(element: KtCallableDeclaration, caretOffset: Int): Boolean {
+ if (element !is KtProperty && element !is KtNamedFunction) {
+ return false
+ }
+ if (element.hasModifier(KtTokens.OPEN_KEYWORD)
+ || element.hasModifier(KtTokens.ABSTRACT_KEYWORD)
+ || element.hasModifier(KtTokens.PRIVATE_KEYWORD)) {
+ return false
+ }
+ val implicitModality = element.implicitModality()
+ if (implicitModality == KtTokens.OPEN_KEYWORD || implicitModality == KtTokens.ABSTRACT_KEYWORD) return false
+ val ktClassOrObject = element.containingClassOrObject ?: return false
+ return ktClassOrObject.hasModifier(KtTokens.ENUM_KEYWORD)
+ || ktClassOrObject.hasModifier(KtTokens.OPEN_KEYWORD)
+ || ktClassOrObject.hasModifier(KtTokens.ABSTRACT_KEYWORD)
+ || ktClassOrObject.hasModifier(KtTokens.SEALED_KEYWORD)
+ }
+
+ override fun applyTo(element: KtCallableDeclaration, editor: Editor?) {
+ element.addModifier(KtTokens.OPEN_KEYWORD)
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/addOpenModifier/.intention b/idea/testData/intentions/addOpenModifier/.intention
new file mode 100644
index 00000000000..f83a0b94391
--- /dev/null
+++ b/idea/testData/intentions/addOpenModifier/.intention
@@ -0,0 +1 @@
+org.jetbrains.kotlin.idea.intentions.AddOpenModifierIntention
diff --git a/idea/testData/intentions/addOpenModifier/abstractClass.kt b/idea/testData/intentions/addOpenModifier/abstractClass.kt
new file mode 100644
index 00000000000..896d9299c81
--- /dev/null
+++ b/idea/testData/intentions/addOpenModifier/abstractClass.kt
@@ -0,0 +1,4 @@
+abstract class Foo {
+ fun bar() {
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/addOpenModifier/abstractClass.kt.after b/idea/testData/intentions/addOpenModifier/abstractClass.kt.after
new file mode 100644
index 00000000000..85b23f6dbb2
--- /dev/null
+++ b/idea/testData/intentions/addOpenModifier/abstractClass.kt.after
@@ -0,0 +1,4 @@
+abstract class Foo {
+ open fun bar() {
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/addOpenModifier/abstractFunction.kt b/idea/testData/intentions/addOpenModifier/abstractFunction.kt
new file mode 100644
index 00000000000..9334d315d53
--- /dev/null
+++ b/idea/testData/intentions/addOpenModifier/abstractFunction.kt
@@ -0,0 +1,5 @@
+// IS_APPLICABLE: false
+
+abstract class Foo {
+ abstract fun bar()
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/addOpenModifier/alreadyOpen.kt b/idea/testData/intentions/addOpenModifier/alreadyOpen.kt
new file mode 100644
index 00000000000..3444cf6c1c3
--- /dev/null
+++ b/idea/testData/intentions/addOpenModifier/alreadyOpen.kt
@@ -0,0 +1,6 @@
+// IS_APPLICABLE: false
+
+open class Foo {
+ open fun bar() {
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/addOpenModifier/destructuringDeclaration.kt b/idea/testData/intentions/addOpenModifier/destructuringDeclaration.kt
new file mode 100644
index 00000000000..82e42479412
--- /dev/null
+++ b/idea/testData/intentions/addOpenModifier/destructuringDeclaration.kt
@@ -0,0 +1,7 @@
+// IS_APPLICABLE: false
+
+data class Bar(val foo: Int, val bar: Int)
+
+open class Foo {
+ var (foo, bar) = Bar(1, 1)
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/addOpenModifier/enumClass.kt b/idea/testData/intentions/addOpenModifier/enumClass.kt
new file mode 100644
index 00000000000..56a7c80ab6e
--- /dev/null
+++ b/idea/testData/intentions/addOpenModifier/enumClass.kt
@@ -0,0 +1,5 @@
+enum class E {
+ SINGLE;
+
+ fun bar() {}
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/addOpenModifier/enumClass.kt.after b/idea/testData/intentions/addOpenModifier/enumClass.kt.after
new file mode 100644
index 00000000000..3e548ab9ccf
--- /dev/null
+++ b/idea/testData/intentions/addOpenModifier/enumClass.kt.after
@@ -0,0 +1,5 @@
+enum class E {
+ SINGLE;
+
+ open fun bar() {}
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/addOpenModifier/function.kt b/idea/testData/intentions/addOpenModifier/function.kt
new file mode 100644
index 00000000000..a0e000225f5
--- /dev/null
+++ b/idea/testData/intentions/addOpenModifier/function.kt
@@ -0,0 +1,4 @@
+open class Foo {
+ fun bar() {
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/addOpenModifier/function.kt.after b/idea/testData/intentions/addOpenModifier/function.kt.after
new file mode 100644
index 00000000000..6ce57d115af
--- /dev/null
+++ b/idea/testData/intentions/addOpenModifier/function.kt.after
@@ -0,0 +1,4 @@
+open class Foo {
+ open fun bar() {
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/addOpenModifier/interface.kt b/idea/testData/intentions/addOpenModifier/interface.kt
new file mode 100644
index 00000000000..907a55dfa49
--- /dev/null
+++ b/idea/testData/intentions/addOpenModifier/interface.kt
@@ -0,0 +1,5 @@
+// IS_APPLICABLE: false
+
+interface Foo {
+ fun bar()
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/addOpenModifier/localFunction.kt b/idea/testData/intentions/addOpenModifier/localFunction.kt
new file mode 100644
index 00000000000..a27e49c03ed
--- /dev/null
+++ b/idea/testData/intentions/addOpenModifier/localFunction.kt
@@ -0,0 +1,9 @@
+// IS_APPLICABLE: false
+
+open class Foo {
+ fun bar() {
+ fun foo() {
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/addOpenModifier/localProperty.kt b/idea/testData/intentions/addOpenModifier/localProperty.kt
new file mode 100644
index 00000000000..bc8a6ee0972
--- /dev/null
+++ b/idea/testData/intentions/addOpenModifier/localProperty.kt
@@ -0,0 +1,7 @@
+// IS_APPLICABLE: false
+
+open class Foo {
+ fun bar() {
+ var foo = 1
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/addOpenModifier/notOpen.kt b/idea/testData/intentions/addOpenModifier/notOpen.kt
new file mode 100644
index 00000000000..a8f1805eb93
--- /dev/null
+++ b/idea/testData/intentions/addOpenModifier/notOpen.kt
@@ -0,0 +1,6 @@
+// IS_APPLICABLE: false
+
+class Foo {
+ fun bar() {
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/addOpenModifier/parameter.kt b/idea/testData/intentions/addOpenModifier/parameter.kt
new file mode 100644
index 00000000000..a199d260ea2
--- /dev/null
+++ b/idea/testData/intentions/addOpenModifier/parameter.kt
@@ -0,0 +1,6 @@
+// IS_APPLICABLE: false
+
+open class Foo {
+ open fun bar(foo: Int) {
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/addOpenModifier/private.kt b/idea/testData/intentions/addOpenModifier/private.kt
new file mode 100644
index 00000000000..de6aa348e00
--- /dev/null
+++ b/idea/testData/intentions/addOpenModifier/private.kt
@@ -0,0 +1,6 @@
+// IS_APPLICABLE: false
+
+open class Foo {
+ private fun bar() {
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/addOpenModifier/property.kt b/idea/testData/intentions/addOpenModifier/property.kt
new file mode 100644
index 00000000000..a8dac6322fd
--- /dev/null
+++ b/idea/testData/intentions/addOpenModifier/property.kt
@@ -0,0 +1,3 @@
+open class Foo {
+ var bar = 0
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/addOpenModifier/property.kt.after b/idea/testData/intentions/addOpenModifier/property.kt.after
new file mode 100644
index 00000000000..519bcb0abd5
--- /dev/null
+++ b/idea/testData/intentions/addOpenModifier/property.kt.after
@@ -0,0 +1,3 @@
+open class Foo {
+ open var bar = 0
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/addOpenModifier/sealedClass.kt b/idea/testData/intentions/addOpenModifier/sealedClass.kt
new file mode 100644
index 00000000000..91059494c70
--- /dev/null
+++ b/idea/testData/intentions/addOpenModifier/sealedClass.kt
@@ -0,0 +1,4 @@
+sealed class Foo {
+ fun bar() {
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/addOpenModifier/sealedClass.kt.after b/idea/testData/intentions/addOpenModifier/sealedClass.kt.after
new file mode 100644
index 00000000000..04e2476c6fe
--- /dev/null
+++ b/idea/testData/intentions/addOpenModifier/sealedClass.kt.after
@@ -0,0 +1,4 @@
+sealed class Foo {
+ open fun bar() {
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/quickfix/removeUnused/triangle.kt b/idea/testData/quickfix/removeUnused/triangle.kt
index e8d47943938..a03fcd5b9c9 100644
--- a/idea/testData/quickfix/removeUnused/triangle.kt
+++ b/idea/testData/quickfix/removeUnused/triangle.kt
@@ -4,6 +4,7 @@
// ACTION: Convert to block body
// ACTION: Move to companion object
// ACTION: Specify return type explicitly
+// ACTION: Make open
interface Inter {
fun something(): String
diff --git a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java
index be897dd03d1..6d9b7fe59bd 100644
--- a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java
+++ b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java
@@ -531,6 +531,99 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
}
}
+ @TestMetadata("idea/testData/intentions/addOpenModifier")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class AddOpenModifier extends AbstractIntentionTest {
+ @TestMetadata("abstractClass.kt")
+ public void testAbstractClass() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/addOpenModifier/abstractClass.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("abstractFunction.kt")
+ public void testAbstractFunction() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/addOpenModifier/abstractFunction.kt");
+ doTest(fileName);
+ }
+
+ public void testAllFilesPresentInAddOpenModifier() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/intentions/addOpenModifier"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), TargetBackend.ANY, true);
+ }
+
+ @TestMetadata("alreadyOpen.kt")
+ public void testAlreadyOpen() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/addOpenModifier/alreadyOpen.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("destructuringDeclaration.kt")
+ public void testDestructuringDeclaration() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/addOpenModifier/destructuringDeclaration.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("enumClass.kt")
+ public void testEnumClass() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/addOpenModifier/enumClass.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("function.kt")
+ public void testFunction() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/addOpenModifier/function.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("interface.kt")
+ public void testInterface() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/addOpenModifier/interface.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("localFunction.kt")
+ public void testLocalFunction() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/addOpenModifier/localFunction.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("localProperty.kt")
+ public void testLocalProperty() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/addOpenModifier/localProperty.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("notOpen.kt")
+ public void testNotOpen() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/addOpenModifier/notOpen.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("parameter.kt")
+ public void testParameter() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/addOpenModifier/parameter.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("private.kt")
+ public void testPrivate() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/addOpenModifier/private.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("property.kt")
+ public void testProperty() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/addOpenModifier/property.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("sealedClass.kt")
+ public void testSealedClass() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/addOpenModifier/sealedClass.kt");
+ doTest(fileName);
+ }
+ }
+
@TestMetadata("idea/testData/intentions/addOperatorModifier")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)