From 48022d959ea3f3fababfc8881f6c76adedd52568 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Wed, 26 Jun 2024 16:09:28 +0200 Subject: [PATCH] K2: support creating class from usage from import directive (part of KTIJ-28671 K2: CreateClassFromUsageFix) GitOrigin-RevId: 47c044231f74811fc51a645c3c67814ae28cddf1 --- .../idea/refactoring/javaTransformUtil.kt | 2 +- .../tests/K2CreateClassFromUsageTest.kt | 4 ++- .../K2CreateClassFromUsageBuilder.kt | 25 ------------------- .../K2CreateFromUsageQuickFixesRegistrar.kt | 20 +++++++++++++++ ...ithJavaQualifier.after.fir.Dependency.java | 5 ++++ ...ithJavaQualifier.after.fir.Dependency.java | 4 +++ ...ithJavaQualifier.after.fir.Dependency.java | 5 ++++ ...tedJavaQualifier.after.fir.Dependency.java | 5 ++++ 8 files changed, 43 insertions(+), 27 deletions(-) create mode 100644 plugins/kotlin/idea/tests/testData/quickfix/createFromUsage/createClass/importDirective/annotationWithJavaQualifier.after.fir.Dependency.java create mode 100644 plugins/kotlin/idea/tests/testData/quickfix/createFromUsage/createClass/importDirective/enumWithJavaQualifier.after.fir.Dependency.java create mode 100644 plugins/kotlin/idea/tests/testData/quickfix/createFromUsage/createClass/importDirective/interfaceWithJavaQualifier.after.fir.Dependency.java create mode 100644 plugins/kotlin/idea/tests/testData/quickfix/createFromUsage/createClass/referenceExpression/interfaceByNestedJavaQualifier.after.fir.Dependency.java diff --git a/plugins/kotlin/code-insight/impl-base/src/org/jetbrains/kotlin/idea/refactoring/javaTransformUtil.kt b/plugins/kotlin/code-insight/impl-base/src/org/jetbrains/kotlin/idea/refactoring/javaTransformUtil.kt index 6460afac23ef..727e59fe8b68 100644 --- a/plugins/kotlin/code-insight/impl-base/src/org/jetbrains/kotlin/idea/refactoring/javaTransformUtil.kt +++ b/plugins/kotlin/code-insight/impl-base/src/org/jetbrains/kotlin/idea/refactoring/javaTransformUtil.kt @@ -147,7 +147,7 @@ fun createJavaClass(klass: KtClass, targetClass: PsiClass?, classKind: ClassKind val template = klass.toLightClass() ?: KotlinAsJavaSupport.getInstance(klass.project).getFakeLightClass(klass) copyModifierListItems(template.modifierList!!, javaClass.modifierList!!) - if (targetClass?.parent is PsiFile) { + if (targetClass?.parent is PsiFile && classKind == ClassKind.CLASS) { javaClass.modifierList!!.setModifierProperty(PsiModifier.STATIC, true) } if (template.isInterface) { diff --git a/plugins/kotlin/code-insight/inspections-k2/tests/test/org/jetbrains/kotlin/idea/k2/quickfix/tests/K2CreateClassFromUsageTest.kt b/plugins/kotlin/code-insight/inspections-k2/tests/test/org/jetbrains/kotlin/idea/k2/quickfix/tests/K2CreateClassFromUsageTest.kt index 058d9353aa7b..4b5fcfdb6131 100644 --- a/plugins/kotlin/code-insight/inspections-k2/tests/test/org/jetbrains/kotlin/idea/k2/quickfix/tests/K2CreateClassFromUsageTest.kt +++ b/plugins/kotlin/code-insight/inspections-k2/tests/test/org/jetbrains/kotlin/idea/k2/quickfix/tests/K2CreateClassFromUsageTest.kt @@ -12,7 +12,9 @@ abstract class K2CreateClassFromUsageTest : K2AbstractCreateFromUsageTest("creat //class AnnotationEntry : K2CreateClassFromUsageTest() //class CallExpression : K2CreateClassFromUsageTest() //class DelegationSpecifier : K2CreateClassFromUsageTest() - //class ImportDirective : K2CreateClassFromUsageTest() + class ImportDirective : K2CreateClassFromUsageTest() { + //class Kt21515: K2CreateClassFromUsageTest() + } class ReferenceExpression : K2CreateClassFromUsageTest() //class TypeReference : K2CreateClassFromUsageTest() } \ No newline at end of file diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/src/org/jetbrains/kotlin/idea/k2/codeinsight/quickFixes/createFromUsage/K2CreateClassFromUsageBuilder.kt b/plugins/kotlin/code-insight/kotlin.code-insight.k2/src/org/jetbrains/kotlin/idea/k2/codeinsight/quickFixes/createFromUsage/K2CreateClassFromUsageBuilder.kt index 64b6a81b3060..f316f6876f27 100644 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/src/org/jetbrains/kotlin/idea/k2/codeinsight/quickFixes/createFromUsage/K2CreateClassFromUsageBuilder.kt +++ b/plugins/kotlin/code-insight/kotlin.code-insight.k2/src/org/jetbrains/kotlin/idea/k2/codeinsight/quickFixes/createFromUsage/K2CreateClassFromUsageBuilder.kt @@ -30,12 +30,8 @@ import org.jetbrains.kotlin.utils.ifEmpty object K2CreateClassFromUsageBuilder { fun generateCreateClassActions(element: KtElement): List { - //if (true) return listOf() val refExpr = element.findParentOfType(strict = false) ?: return listOf() - //if (refExpr.getQualifiedElement() != refExpr) return listOf() if (refExpr.getParentOfTypeAndBranch { callableReference } != null) return listOf() - //val targetParents = mutableListOf() - val qualifiedElement = refExpr.getQualifiedElement() var expectedType: ExpectedKotlinType? var superClassName:String? @@ -50,27 +46,6 @@ object K2CreateClassFromUsageBuilder { paramList = renderParamList(superClass, isAny) returnTypeString = if (superClass == null || superClassName == null || isAny) "" else if (superClass!!.isInterface()) ": $superClassName" else ": $superClassName()" - //if (qualifiedElement == refExpr) { - // // not qualified - // targetParents.addAll(element.parents.filterIsInstance().toList()) - // targetParents += element.containingFile - //} - //else { - // val receiver = - // when (qualifiedElement) { - // is KtQualifiedExpression -> qualifiedElement.receiverExpression.resolveExpression() - // is KtUserType -> null - // else -> null - // } - // - // receiver?.psi?.let { targetParents += it } - //} - - //if (targetParents.isEmpty()) { - // targetParents += element.containingFile - //} - //if (getContainer(refExpr) == null) return null - val (classKinds, targetParents) = getPossibleClassKindsAndParents(refExpr) return classKinds.map { kind -> val applicableParents = targetParents diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/src/org/jetbrains/kotlin/idea/k2/codeinsight/quickFixes/createFromUsage/K2CreateFromUsageQuickFixesRegistrar.kt b/plugins/kotlin/code-insight/kotlin.code-insight.k2/src/org/jetbrains/kotlin/idea/k2/codeinsight/quickFixes/createFromUsage/K2CreateFromUsageQuickFixesRegistrar.kt index 7a2f793f5e0b..2f35ee3ba6a3 100644 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/src/org/jetbrains/kotlin/idea/k2/codeinsight/quickFixes/createFromUsage/K2CreateFromUsageQuickFixesRegistrar.kt +++ b/plugins/kotlin/code-insight/kotlin.code-insight.k2/src/org/jetbrains/kotlin/idea/k2/codeinsight/quickFixes/createFromUsage/K2CreateFromUsageQuickFixesRegistrar.kt @@ -1,6 +1,8 @@ // Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package org.jetbrains.kotlin.idea.k2.codeinsight.quickFixes.createFromUsage +import K2CreateClassFromUsageBuilder +import com.intellij.codeInsight.intention.IntentionAction import com.intellij.psi.util.PsiTreeUtil import org.jetbrains.kotlin.analysis.api.fir.diagnostics.KaFirDiagnostic import org.jetbrains.kotlin.idea.codeinsight.api.applicators.fixes.KotlinQuickFixFactory @@ -8,6 +10,8 @@ import org.jetbrains.kotlin.idea.codeinsight.api.applicators.fixes.KotlinQuickFi import org.jetbrains.kotlin.idea.codeinsight.api.applicators.fixes.KotlinQuickFixesList import org.jetbrains.kotlin.idea.codeinsight.api.applicators.fixes.KtQuickFixesListBuilder import org.jetbrains.kotlin.psi.KtCallExpression +import org.jetbrains.kotlin.psi.KtElement +import org.jetbrains.kotlin.psi.KtImportDirective import org.jetbrains.kotlin.psi.KtQualifiedExpression class K2CreateFromUsageQuickFixesRegistrar : KotlinQuickFixRegistrar() { @@ -56,6 +60,21 @@ class K2CreateFromUsageQuickFixesRegistrar : KotlinQuickFixRegistrar() { KotlinQuickFixFactory.IntentionBased { diagnostic: KaFirDiagnostic.ComponentFunctionMissing -> listOfNotNull(K2CreateParameterFromUsageBuilder.generateCreateParameterActionForComponentFunctionMissing(diagnostic.psi, diagnostic.destructingType)) } + private val createClassFromUsageForUnresolvedImport: KotlinQuickFixFactory.IntentionBased = + KotlinQuickFixFactory.IntentionBased { diagnostic: KaFirDiagnostic.UnresolvedImport -> + createClassFromUsageForUnresolvedImport(diagnostic) + } + + private fun createClassFromUsageForUnresolvedImport(diagnostic: KaFirDiagnostic.UnresolvedImport): List { + val unresolvedName = diagnostic.reference + val simpleReferences = (diagnostic.psi as KtImportDirective).importedReference?.children ?: emptyArray() + for (simpleReference in simpleReferences) { + if (unresolvedName == simpleReference.text) { + return K2CreateClassFromUsageBuilder.generateCreateClassActions(simpleReference as KtElement) + } + } + return listOf() + } override val list: KotlinQuickFixesList = KtQuickFixesListBuilder.registerPsiQuickFix { registerFactory(createFunctionForArgumentTypeMismatch) @@ -64,5 +83,6 @@ class K2CreateFromUsageQuickFixesRegistrar : KotlinQuickFixRegistrar() { registerFactory(createVariableForExpressionExpectedPackageFound) registerFactory(createParameterForNamedParameterNotFound) registerFactory(createParameterForComponentFunctionMissing) + registerFactory(createClassFromUsageForUnresolvedImport) } } \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/quickfix/createFromUsage/createClass/importDirective/annotationWithJavaQualifier.after.fir.Dependency.java b/plugins/kotlin/idea/tests/testData/quickfix/createFromUsage/createClass/importDirective/annotationWithJavaQualifier.after.fir.Dependency.java new file mode 100644 index 000000000000..0581d452b268 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/quickfix/createFromUsage/createClass/importDirective/annotationWithJavaQualifier.after.fir.Dependency.java @@ -0,0 +1,5 @@ +public class J { + + public @interface A { + } +} diff --git a/plugins/kotlin/idea/tests/testData/quickfix/createFromUsage/createClass/importDirective/enumWithJavaQualifier.after.fir.Dependency.java b/plugins/kotlin/idea/tests/testData/quickfix/createFromUsage/createClass/importDirective/enumWithJavaQualifier.after.fir.Dependency.java new file mode 100644 index 000000000000..8c960a7a8ee0 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/quickfix/createFromUsage/createClass/importDirective/enumWithJavaQualifier.after.fir.Dependency.java @@ -0,0 +1,4 @@ +public class J { + + public enum A {} +} diff --git a/plugins/kotlin/idea/tests/testData/quickfix/createFromUsage/createClass/importDirective/interfaceWithJavaQualifier.after.fir.Dependency.java b/plugins/kotlin/idea/tests/testData/quickfix/createFromUsage/createClass/importDirective/interfaceWithJavaQualifier.after.fir.Dependency.java new file mode 100644 index 000000000000..3e35affb9bcf --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/quickfix/createFromUsage/createClass/importDirective/interfaceWithJavaQualifier.after.fir.Dependency.java @@ -0,0 +1,5 @@ +public class J { + + public interface A { + } +} diff --git a/plugins/kotlin/idea/tests/testData/quickfix/createFromUsage/createClass/referenceExpression/interfaceByNestedJavaQualifier.after.fir.Dependency.java b/plugins/kotlin/idea/tests/testData/quickfix/createFromUsage/createClass/referenceExpression/interfaceByNestedJavaQualifier.after.fir.Dependency.java new file mode 100644 index 000000000000..011cd6d6d40c --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/quickfix/createFromUsage/createClass/referenceExpression/interfaceByNestedJavaQualifier.after.fir.Dependency.java @@ -0,0 +1,5 @@ +class J { + + public interface A { + } +}