mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[kotlin] Introduce "Add 'fun' modifier" quick-fix for RESOLUTION_TO_CLASSIFIER
^KTIJ-16332 Fixed closes https://github.com/JetBrains/intellij-community/pull/2155 GitOrigin-RevId: 373f07b8aa05e4bfb5da513a05810dcae5e4230d
This commit is contained in:
committed by
intellij-monorepo-bot
parent
5d04acf825
commit
e2a67ba0dc
@@ -2523,3 +2523,5 @@ inspection.convert.object.to.data.object.display.name=Convert 'object' to 'data
|
||||
|
||||
inspection.replace.with.string.builder.append.range.display.name='StringBuilder.append(CharArray, offset, len)' call on the JVM
|
||||
progress.title.collect.hierarchy=Collect ''{0}'' hierarchy ...
|
||||
|
||||
add.fun.modifier.to.0=Add ''fun'' modifier to ''{0}''
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.kotlin.idea.quickfix
|
||||
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.SmartPsiElementPointer
|
||||
import com.intellij.refactoring.suggested.createSmartPointer
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.psiElement
|
||||
import org.jetbrains.kotlin.config.LanguageVersion
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.idea.base.projectStructure.languageVersionSettings
|
||||
import org.jetbrains.kotlin.idea.base.resources.KotlinBundle
|
||||
import org.jetbrains.kotlin.idea.core.canMoveLambdaOutsideParentheses
|
||||
import org.jetbrains.kotlin.idea.core.moveFunctionLiteralOutsideParentheses
|
||||
import org.jetbrains.kotlin.idea.inspections.RedundantSamConstructorInspection
|
||||
import org.jetbrains.kotlin.idea.util.application.runWriteActionIfPhysical
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.KtCallExpression
|
||||
import org.jetbrains.kotlin.psi.KtClass
|
||||
import org.jetbrains.kotlin.psi.KtLambdaArgument
|
||||
import org.jetbrains.kotlin.psi.KtValueArgument
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||
import org.jetbrains.kotlin.resolve.sam.getAbstractMembers
|
||||
|
||||
class AddFunModifierFix(
|
||||
element: KtClass,
|
||||
private val elementName: String,
|
||||
private val referrerCall: SmartPsiElementPointer<KtCallExpression>
|
||||
) : AddModifierFixFE10(element, KtTokens.FUN_KEYWORD) {
|
||||
override fun getText() = KotlinBundle.message("add.fun.modifier.to.0", elementName)
|
||||
|
||||
override fun getFamilyName() = text
|
||||
|
||||
override fun invokeImpl(project: Project, editor: Editor?, file: PsiFile) {
|
||||
super.invokeImpl(project, editor, file)
|
||||
referrerCall.element?.removeRedundantSamConstructor()
|
||||
}
|
||||
|
||||
private fun KtCallExpression.removeRedundantSamConstructor() {
|
||||
if (lambdaArguments.singleOrNull() == null) return
|
||||
val argument = getStrictParentOfType<KtValueArgument>()?.takeIf { it.getArgumentExpression() == this } ?: return
|
||||
val parentCall = argument.getStrictParentOfType<KtCallExpression>() ?: return
|
||||
|
||||
RedundantSamConstructorInspection.replaceSamConstructorCall(this)
|
||||
|
||||
if (parentCall.canMoveLambdaOutsideParentheses()) {
|
||||
runWriteActionIfPhysical(parentCall) {
|
||||
parentCall.moveFunctionLiteralOutsideParentheses()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object : KotlinSingleIntentionActionFactory() {
|
||||
override fun createAction(diagnostic: Diagnostic): IntentionAction? {
|
||||
val casted = Errors.RESOLUTION_TO_CLASSIFIER.cast(diagnostic)
|
||||
val referrer = casted.psiElement
|
||||
if (referrer.languageVersionSettings.languageVersion < LanguageVersion.KOTLIN_1_4) return null
|
||||
|
||||
val referrerCall = referrer.parent as? KtCallExpression ?: return null
|
||||
if (referrerCall.valueArguments.singleOrNull() !is KtLambdaArgument) return null
|
||||
|
||||
val referenceClassDescriptor = casted.a as? ClassDescriptor ?: return null
|
||||
if (referenceClassDescriptor.isFun || !referenceClassDescriptor.isSamInterface()) return null
|
||||
|
||||
val referenceClass = referenceClassDescriptor.psiElement as? KtClass ?: return null
|
||||
val referenceClassName = referenceClass.name ?: return null
|
||||
return AddFunModifierFix(referenceClass, referenceClassName, referrerCall.createSmartPointer())
|
||||
}
|
||||
|
||||
private fun ClassDescriptor.isSamInterface(): Boolean {
|
||||
if (kind != ClassKind.INTERFACE) return false
|
||||
val singleAbstractMember = getAbstractMembers(this).singleOrNull() ?: return false
|
||||
return singleAbstractMember is SimpleFunctionDescriptor && singleAbstractMember.typeParameters.isEmpty()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -678,7 +678,7 @@ class QuickFixRegistrar : QuickFixContributor {
|
||||
DEFAULT_VALUE_NOT_ALLOWED_IN_OVERRIDE.registerFactory(RemoveDefaultParameterValueFix)
|
||||
ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS.registerFactory(RemoveDefaultParameterValueFix)
|
||||
|
||||
RESOLUTION_TO_CLASSIFIER.registerFactory(ConvertToAnonymousObjectFix)
|
||||
RESOLUTION_TO_CLASSIFIER.registerFactory(ConvertToAnonymousObjectFix, AddFunModifierFix)
|
||||
|
||||
NOTHING_TO_INLINE.registerFactory(RemoveModifierFixBase.removeNonRedundantModifier)
|
||||
|
||||
|
||||
+48
@@ -1002,6 +1002,54 @@ public abstract class QuickFixTestGenerated extends AbstractQuickFixTest {
|
||||
}
|
||||
}
|
||||
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
@TestMetadata("testData/quickfix/addFunModifier")
|
||||
public static class AddFunModifier extends AbstractQuickFixTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
|
||||
}
|
||||
|
||||
@TestMetadata("asFirstArgument.kt")
|
||||
public void testAsFirstArgument() throws Exception {
|
||||
runTest("testData/quickfix/addFunModifier/asFirstArgument.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("asLastArgument.kt")
|
||||
public void testAsLastArgument() throws Exception {
|
||||
runTest("testData/quickfix/addFunModifier/asLastArgument.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("hasArguments.kt")
|
||||
public void testHasArguments() throws Exception {
|
||||
runTest("testData/quickfix/addFunModifier/hasArguments.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("hasNoArguments.kt")
|
||||
public void testHasNoArguments() throws Exception {
|
||||
runTest("testData/quickfix/addFunModifier/hasNoArguments.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("notSam.kt")
|
||||
public void testNotSam() throws Exception {
|
||||
runTest("testData/quickfix/addFunModifier/notSam.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("notSam2.kt")
|
||||
public void testNotSam2() throws Exception {
|
||||
runTest("testData/quickfix/addFunModifier/notSam2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("notSam3.kt")
|
||||
public void testNotSam3() throws Exception {
|
||||
runTest("testData/quickfix/addFunModifier/notSam3.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("simple.kt")
|
||||
public void testSimple() throws Exception {
|
||||
runTest("testData/quickfix/addFunModifier/simple.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
@TestMetadata("testData/quickfix/addGenericUpperBound")
|
||||
public static class AddGenericUpperBound extends AbstractQuickFixTest {
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
// "Add 'fun' modifier to 'I'" "true"
|
||||
interface I {
|
||||
fun f()
|
||||
}
|
||||
|
||||
fun foo(i: I, j: Int) {}
|
||||
|
||||
fun test() {
|
||||
val x = foo(<caret>I {}, 2)
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// "Add 'fun' modifier to 'I'" "true"
|
||||
fun interface I {
|
||||
fun f()
|
||||
}
|
||||
|
||||
fun foo(i: I, j: Int) {}
|
||||
|
||||
fun test() {
|
||||
val x = foo({}, 2)
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// "Add 'fun' modifier to 'I'" "true"
|
||||
interface I {
|
||||
fun f()
|
||||
}
|
||||
|
||||
fun foo(i: I) {}
|
||||
|
||||
fun test() {
|
||||
val x = foo(<caret>I {})
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// "Add 'fun' modifier to 'I'" "true"
|
||||
fun interface I {
|
||||
fun f()
|
||||
}
|
||||
|
||||
fun foo(i: I) {}
|
||||
|
||||
fun test() {
|
||||
val x = foo {}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// "Add 'fun' modifier to 'I'" "false"
|
||||
// DISABLE-ERRORS
|
||||
// ACTION: Convert to anonymous object
|
||||
// ACTION: Introduce import alias
|
||||
// ACTION: Split property declaration
|
||||
interface I {
|
||||
fun f()
|
||||
}
|
||||
|
||||
fun test() {
|
||||
val x = <caret>I(1) {}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// "Add 'fun' modifier to 'I'" "false"
|
||||
// DISABLE-ERRORS
|
||||
// ACTION: Introduce import alias
|
||||
// ACTION: Split property declaration
|
||||
interface I {
|
||||
fun f()
|
||||
}
|
||||
|
||||
fun test() {
|
||||
val x = <caret>I()
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// "Add 'fun' modifier to 'I'" "false"
|
||||
// DISABLE-ERRORS
|
||||
// ACTION: Introduce import alias
|
||||
// ACTION: Split property declaration
|
||||
interface I {
|
||||
fun f() {}
|
||||
}
|
||||
|
||||
fun test() {
|
||||
val x = <caret>I {}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// "Add 'fun' modifier to 'I'" "false"
|
||||
// DISABLE-ERRORS
|
||||
// ACTION: Introduce import alias
|
||||
// ACTION: Split property declaration
|
||||
interface I {
|
||||
fun f()
|
||||
fun g()
|
||||
}
|
||||
|
||||
fun test() {
|
||||
val x = <caret>I {}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// "Add 'fun' modifier to 'I'" "false"
|
||||
// DISABLE-ERRORS
|
||||
// ACTION: Introduce import alias
|
||||
// ACTION: Split property declaration
|
||||
interface I {
|
||||
fun <T> f()
|
||||
}
|
||||
|
||||
fun test() {
|
||||
val x = <caret>I {}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// "Add 'fun' modifier to 'I'" "true"
|
||||
interface I {
|
||||
fun f()
|
||||
}
|
||||
|
||||
fun test() {
|
||||
val x = <caret>I {}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// "Add 'fun' modifier to 'I'" "true"
|
||||
fun interface I {
|
||||
fun f()
|
||||
}
|
||||
|
||||
fun test() {
|
||||
val x = I {}
|
||||
}
|
||||
@@ -80,4 +80,5 @@ com.intellij.spring.model.highlighting.autowire.SpringUastInjectionPointsAutowir
|
||||
org.jetbrains.kotlin.idea.compilerPlugin.parcelize.quickfixes.ParcelMigrateToParcelizeQuickFix
|
||||
org.jetbrains.kotlin.idea.quickfix.AddConversionCallFix
|
||||
org.jetbrains.kotlin.idea.quickfix.OverloadResolutionChangeFix
|
||||
org.jetbrains.kotlin.idea.quickfix.AbstractSuperCallFix
|
||||
org.jetbrains.kotlin.idea.quickfix.AbstractSuperCallFix
|
||||
org.jetbrains.kotlin.idea.quickfix.AddFunModifierFix
|
||||
|
||||
Reference in New Issue
Block a user