Quick-fix to add noinline to parameter with suspend function type + AddInlineModifierFix refactoring #KT-16074 Fixed

This commit is contained in:
Mikhail Glukhikh
2017-02-15 20:25:14 +03:00
parent d9710ea4ff
commit 0432e2e947
6 changed files with 42 additions and 25 deletions
@@ -17,8 +17,6 @@
package org.jetbrains.kotlin.idea.quickfix package org.jetbrains.kotlin.idea.quickfix
import com.intellij.codeInsight.intention.IntentionAction import com.intellij.codeInsight.intention.IntentionAction
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
@@ -27,38 +25,43 @@ import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
class AddInlineModifierFix( class AddInlineModifierFix(
element: KtNameReferenceExpression, parameter: KtParameter,
private val modifier: KtModifierKeywordToken modifier: KtModifierKeywordToken
) : KotlinQuickFixAction<KtNameReferenceExpression>(element) { ) : AddModifierFix(parameter, modifier) {
override fun getText() = element?.let { "Add '${modifier.value}' to parameter '${it.getReferencedName()}'" } ?: ""
override fun getText() = element?.let { "Add '${modifier.value}' to parameter '${it.name}'" } ?: ""
override fun getFamilyName() = "Add '${modifier.value}' to parameter" override fun getFamilyName() = "Add '${modifier.value}' to parameter"
override fun invoke(project: Project, editor: Editor?, file: KtFile) { companion object {
val element = element ?: return private fun KtElement.findParameterWithName(name: String): KtParameter? {
val parameter = element.findParameterWithName(element.getReferencedName()) ?: return val function = getStrictParentOfType<KtFunction>() ?: return null
if (!parameter.hasModifier(modifier)) { return function.valueParameters.firstOrNull { it.name == name } ?: function.findParameterWithName(name)
parameter.addModifier(modifier)
} }
} }
private fun KtElement.findParameterWithName(name: String): KtParameter? { object CrossInlineFactory : KotlinSingleIntentionActionFactory() {
val function = getStrictParentOfType<KtFunction>() ?: return null override fun createAction(diagnostic: Diagnostic): IntentionAction? {
return function.valueParameters.firstOrNull { it.name == name } ?: function.findParameterWithName(name)
}
object CrossInlineFactory : KotlinIntentionActionsFactory() {
override fun doCreateActions(diagnostic: Diagnostic): List<IntentionAction> {
val casted = Errors.NON_LOCAL_RETURN_NOT_ALLOWED.cast(diagnostic) val casted = Errors.NON_LOCAL_RETURN_NOT_ALLOWED.cast(diagnostic)
val reference = casted.a as? KtNameReferenceExpression ?: return emptyList() val reference = casted.a as? KtNameReferenceExpression ?: return null
return listOf(AddInlineModifierFix(reference, KtTokens.CROSSINLINE_KEYWORD)) val parameter = reference.findParameterWithName(reference.getReferencedName()) ?: return null
return AddInlineModifierFix(parameter, KtTokens.CROSSINLINE_KEYWORD)
} }
} }
object NoInlineFactory : KotlinIntentionActionsFactory() { object NoInlineFactory : KotlinSingleIntentionActionFactory() {
override fun doCreateActions(diagnostic: Diagnostic): List<IntentionAction> { override fun createAction(diagnostic: Diagnostic): IntentionAction? {
val casted = Errors.USAGE_IS_NOT_INLINABLE.cast(diagnostic) val casted = Errors.USAGE_IS_NOT_INLINABLE.cast(diagnostic)
val reference = casted.a as? KtNameReferenceExpression ?: return emptyList() val reference = casted.a as? KtNameReferenceExpression ?: return null
return listOf(AddInlineModifierFix(reference, KtTokens.NOINLINE_KEYWORD)) val parameter = reference.findParameterWithName(reference.getReferencedName()) ?: return null
return AddInlineModifierFix(parameter, KtTokens.NOINLINE_KEYWORD)
} }
} }
object SuspendFactory : KotlinSingleIntentionActionFactory() {
override fun createAction(diagnostic: Diagnostic): IntentionAction? {
val parameter = diagnostic.psiElement as? KtParameter ?: return null
return AddInlineModifierFix(parameter, KtTokens.NOINLINE_KEYWORD)
}
}
} }
@@ -37,7 +37,7 @@ import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
open class AddModifierFix( open class AddModifierFix(
element: KtModifierListOwner, element: KtModifierListOwner,
private val modifier: KtModifierKeywordToken protected val modifier: KtModifierKeywordToken
) : KotlinQuickFixAction<KtModifierListOwner>(element) { ) : KotlinQuickFixAction<KtModifierListOwner>(element) {
override fun getText(): String { override fun getText(): String {
@@ -470,6 +470,8 @@ class QuickFixRegistrar : QuickFixContributor {
ErrorsJs.WRONG_EXTERNAL_DECLARATION.registerFactory(MigrateExternalExtensionFix) ErrorsJs.WRONG_EXTERNAL_DECLARATION.registerFactory(MigrateExternalExtensionFix)
ILLEGAL_SUSPEND_FUNCTION_CALL.registerFactory(AddSuspendModifierFix) ILLEGAL_SUSPEND_FUNCTION_CALL.registerFactory(AddSuspendModifierFix)
INLINE_SUSPEND_FUNCTION_TYPE_UNSUPPORTED.registerFactory(AddInlineModifierFix.SuspendFactory)
UNRESOLVED_REFERENCE.registerFactory(AddSuspendModifierFix.UnresolvedReferenceFactory) UNRESOLVED_REFERENCE.registerFactory(AddSuspendModifierFix.UnresolvedReferenceFactory)
UNRESOLVED_REFERENCE_WRONG_RECEIVER.registerFactory(AddSuspendModifierFix.UnresolvedReferenceFactory) UNRESOLVED_REFERENCE_WRONG_RECEIVER.registerFactory(AddSuspendModifierFix.UnresolvedReferenceFactory)
+3
View File
@@ -0,0 +1,3 @@
// "Add 'noinline' to parameter 'x'" "true"
inline fun foo(<caret>x: suspend () -> Unit) {}
+3
View File
@@ -0,0 +1,3 @@
// "Add 'noinline' to parameter 'x'" "true"
inline fun foo(noinline x: suspend () -> Unit) {}
@@ -445,6 +445,12 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/addNoinline/basic.kt"); String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/addNoinline/basic.kt");
doTest(fileName); doTest(fileName);
} }
@TestMetadata("suspend.kt")
public void testSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/addNoinline/suspend.kt");
doTest(fileName);
}
} }
@TestMetadata("idea/testData/quickfix/addReifiedToTypeParameterOfFunctionFix") @TestMetadata("idea/testData/quickfix/addReifiedToTypeParameterOfFunctionFix")