JvmCommonIntentionActionsFactory in Kotlin

This commit is contained in:
Nicolay Mitropolsky
2017-04-27 18:30:12 +03:00
committed by Nikolay Krasko
parent 548e86285c
commit 0694f2d0c5
4 changed files with 169 additions and 12 deletions
+1
View File
@@ -2480,6 +2480,7 @@
<projectOpenProcessor implementation="org.jetbrains.kotlin.gradle.GradleKotlinDSLProjectOpenProcessor"/>
<projectImportProvider implementation="org.jetbrains.kotlin.gradle.GradleKotlinDSLProjectImportProvider"/>
<codeInsight.intention.jvmCommonIntentionActionsFactory language="kotlin" implementationClass="org.jetbrains.kotlin.idea.intentions.KotlinCommonModifications"/>
</extensions>
<extensions defaultExtensionNs="org.jetbrains.uast">
@@ -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
)
}
}
@@ -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() {
@@ -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<caret>(){}
}
""")
myFixture.launchAction(codeModifications.createChangeModifierAction(uastElementAtCaret(myFixture), PsiModifier.FINAL, false )!!)
myFixture.checkResult("""
class Foo {
open fun bar(){}
}
""")
}
fun testMakePrivate() {
myFixture.configureByText("foo.kt", """
class Foo<caret> {
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<caret> {
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<caret>(){}
}
""".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<UDeclaration>(elementAtCaret, null)
}
private val codeModifications: JvmCommonIntentionActionsFactory
get() = JvmCommonIntentionActionsFactory.forLanguage(Language.findLanguageByID("kotlin")!!)
}