diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml
index a8ef8024c22..d5c3697236b 100644
--- a/idea/src/META-INF/plugin.xml
+++ b/idea/src/META-INF/plugin.xml
@@ -2480,6 +2480,7 @@
+
diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/KotlinCommonModifications.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/KotlinCommonModifications.kt
new file mode 100644
index 00000000000..e1684bb35ad
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/intentions/KotlinCommonModifications.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2010-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 org.jetbrains.kotlin.idea.intentions
+
+import com.intellij.codeInsight.intention.*
+import com.intellij.psi.PsiModifier
+import org.jetbrains.kotlin.asJava.elements.KtLightElement
+import org.jetbrains.kotlin.idea.quickfix.AddModifierFix
+import org.jetbrains.kotlin.idea.quickfix.RemoveModifierFix
+import org.jetbrains.kotlin.lexer.KtTokens
+import org.jetbrains.kotlin.psi.KtModifierListOwner
+import org.jetbrains.uast.UDeclaration
+
+
+class KotlinCommonModifications : JvmCommonIntentionActionsFactory() {
+ override fun createChangeModifierAction(declaration: UDeclaration, modifier: String, shouldPresent: Boolean): IntentionAction? {
+ val kModifierOwner = (declaration.psi as? KtLightElement<*, *>?)?.kotlinOrigin as? KtModifierListOwner?
+ ?: throw IllegalArgumentException("$declaration is expected to contain KtLightElement with KtModifierListOwner")
+
+ val (kToken, shouldPresentMapped) = if (PsiModifier.FINAL == modifier)
+ KtTokens.OPEN_KEYWORD to !shouldPresent
+ else
+ javaPsiModifiersMapping[modifier] to shouldPresent
+
+ if (kToken == null) return null
+ return if (shouldPresentMapped)
+ AddModifierFix.createIfApplicable(kModifierOwner, kToken)
+ else
+ RemoveModifierFix(kModifierOwner, kToken, false)
+ }
+
+ companion object {
+ val javaPsiModifiersMapping = mapOf(
+ PsiModifier.PRIVATE to KtTokens.PRIVATE_KEYWORD,
+ PsiModifier.PUBLIC to KtTokens.PUBLIC_KEYWORD,
+ PsiModifier.PROTECTED to KtTokens.PUBLIC_KEYWORD,
+ PsiModifier.ABSTRACT to KtTokens.ABSTRACT_KEYWORD
+ )
+ }
+
+}
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/AddModifierFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/AddModifierFix.kt
index 82369aa9eb0..bc3aa95fd37 100644
--- a/idea/src/org/jetbrains/kotlin/idea/quickfix/AddModifierFix.kt
+++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/AddModifierFix.kt
@@ -100,21 +100,24 @@ open class AddModifierFix(
return object : KotlinSingleIntentionActionFactory() {
public override fun createAction(diagnostic: Diagnostic): IntentionAction? {
val modifierListOwner = QuickFixUtil.getParentElementOfType(diagnostic, modifierOwnerClass) ?: return null
-
- if (modifier == KtTokens.ABSTRACT_KEYWORD) {
- if (modifierListOwner is KtObjectDeclaration) return null
- if (modifierListOwner is KtEnumEntry) return null
- if (modifierListOwner is KtDeclaration && modifierListOwner !is KtClass) {
- val parentClassOrObject = modifierListOwner.containingClassOrObject ?: return null
- if (parentClassOrObject is KtObjectDeclaration) return null
- if (parentClassOrObject is KtEnumEntry) return null
- }
- }
-
- return AddModifierFix(modifierListOwner, modifier)
+ return createIfApplicable(modifierListOwner, modifier)
}
}
}
+
+ fun createIfApplicable(modifierListOwner: KtModifierListOwner, modifier: KtModifierKeywordToken): AddModifierFix? {
+ if (modifier == ABSTRACT_KEYWORD || modifier == OPEN_KEYWORD) {
+ if (modifierListOwner is KtObjectDeclaration) return null
+ if (modifierListOwner is KtEnumEntry) return null
+ if (modifierListOwner is KtDeclaration && modifierListOwner !is KtClass) {
+ val parentClassOrObject = modifierListOwner.containingClassOrObject ?: return null
+ if (parentClassOrObject is KtObjectDeclaration) return null
+ if (parentClassOrObject is KtEnumEntry) return null
+ }
+ }
+ return AddModifierFix(modifierListOwner, modifier)
+ }
+
}
object MakeClassOpenFactory : KotlinSingleIntentionActionFactory() {
diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/CommonModificationsTest.kt b/idea/tests/org/jetbrains/kotlin/idea/quickfix/CommonModificationsTest.kt
new file mode 100644
index 00000000000..44ceba9b303
--- /dev/null
+++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/CommonModificationsTest.kt
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2010-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 org.jetbrains.kotlin.idea.quickfix
+
+import com.intellij.codeInsight.intention.JvmCommonIntentionActionsFactory
+import com.intellij.lang.Language
+import com.intellij.openapi.components.ServiceManager
+import com.intellij.psi.PsiModifier
+import com.intellij.testFramework.fixtures.CodeInsightTestFixture
+import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase
+import org.jetbrains.uast.UDeclaration
+import org.jetbrains.uast.UastContext
+import org.jetbrains.uast.convert
+import org.junit.Assert
+
+
+class CommonModificationsTest : LightPlatformCodeInsightFixtureTestCase() {
+
+ fun testMakeNotFinal() {
+ myFixture.configureByText("foo.kt", """
+ class Foo {
+ fun bar(){}
+ }
+ """)
+
+ myFixture.launchAction(codeModifications.createChangeModifierAction(uastElementAtCaret(myFixture), PsiModifier.FINAL, false )!!)
+ myFixture.checkResult("""
+ class Foo {
+ open fun bar(){}
+ }
+ """)
+ }
+
+ fun testMakePrivate() {
+ myFixture.configureByText("foo.kt", """
+ class Foo {
+ fun bar(){}
+ }
+ """)
+
+ myFixture.launchAction(codeModifications.createChangeModifierAction(uastElementAtCaret(myFixture), PsiModifier.PRIVATE, true )!!)
+ myFixture.checkResult("""
+ private class Foo {
+ fun bar(){}
+ }
+ """)
+ }
+
+ fun testMakeNotPrivate() {
+ myFixture.configureByText("foo.kt", """
+ private class Foo {
+ fun bar(){}
+ }
+ """.trim())
+
+ myFixture.launchAction(codeModifications.createChangeModifierAction(uastElementAtCaret(myFixture), PsiModifier.PRIVATE, false )!!)
+ myFixture.checkResult("""
+ class Foo {
+ fun bar(){}
+ }
+ """.trim(), true)
+ }
+
+ fun testDontMakeFunInObjectsOpen() {
+ myFixture.configureByText("foo.kt", """
+ object Foo {
+ fun bar(){}
+ }
+ """.trim())
+ Assert.assertNull(codeModifications.createChangeModifierAction(uastElementAtCaret(myFixture), PsiModifier.FINAL, false))
+ }
+
+ private fun uastElementAtCaret(myFixture: CodeInsightTestFixture): UDeclaration {
+ val elementAtCaret = myFixture.elementAtCaret
+ val uastContext = ServiceManager.getService(elementAtCaret.project, UastContext::class.java) ?: error("UastContext not found")
+ val uastLanguagePlugin = uastContext.findPlugin(elementAtCaret) ?: error("Language plugin was not found for $this (${this.javaClass.name})")
+ return uastLanguagePlugin.convert(elementAtCaret, null)
+ }
+
+ private val codeModifications: JvmCommonIntentionActionsFactory
+ get() = JvmCommonIntentionActionsFactory.forLanguage(Language.findLanguageByID("kotlin")!!)
+
+}
+