diff --git a/plugins/kotlin/frontend-independent/src/org/jetbrains/kotlin/idea/quickfix/AddDefaultConstructorFix.kt b/plugins/kotlin/frontend-independent/src/org/jetbrains/kotlin/idea/quickfix/AddDefaultConstructorFix.kt new file mode 100644 index 000000000000..7ae5bf882661 --- /dev/null +++ b/plugins/kotlin/frontend-independent/src/org/jetbrains/kotlin/idea/quickfix/AddDefaultConstructorFix.kt @@ -0,0 +1,25 @@ +// 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.quickfix + +import com.intellij.modcommand.ActionContext +import com.intellij.modcommand.ModPsiUpdater +import org.jetbrains.kotlin.idea.base.resources.KotlinBundle +import org.jetbrains.kotlin.idea.codeinsight.api.applicable.intentions.KotlinPsiUpdateModCommandAction +import org.jetbrains.kotlin.psi.KtClass +import org.jetbrains.kotlin.psi.createPrimaryConstructorIfAbsent + +class AddDefaultConstructorFix( + element: KtClass, +) : KotlinPsiUpdateModCommandAction.ElementBased(element, Unit) { + + override fun getFamilyName() = KotlinBundle.message("fix.add.default.constructor") + + override fun invoke( + actionContext: ActionContext, + element: KtClass, + elementContext: Unit, + updater: ModPsiUpdater, + ) { + element.createPrimaryConstructorIfAbsent() + } +} diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/quickfix/AddDefaultConstructorFix.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/quickfix/AddDefaultConstructorFix.kt index 4f2c1d3ee547..ae30f9ef78fb 100644 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/quickfix/AddDefaultConstructorFix.kt +++ b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/quickfix/AddDefaultConstructorFix.kt @@ -3,63 +3,43 @@ package org.jetbrains.kotlin.idea.quickfix import com.intellij.codeInsight.intention.IntentionAction -import com.intellij.modcommand.ActionContext -import com.intellij.modcommand.ModPsiUpdater import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.diagnostics.Diagnostic -import org.jetbrains.kotlin.idea.base.resources.KotlinBundle import org.jetbrains.kotlin.idea.caches.resolve.analyze -import org.jetbrains.kotlin.idea.codeinsight.api.applicable.intentions.KotlinPsiUpdateModCommandAction import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypes import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils -class AddDefaultConstructorFix( - element: KtClass, -) : KotlinPsiUpdateModCommandAction.ElementBased(element, Unit) { - - override fun getFamilyName() = KotlinBundle.message("fix.add.default.constructor") - - override fun invoke( - actionContext: ActionContext, - element: KtClass, - elementContext: Unit, - updater: ModPsiUpdater, - ) { - element.createPrimaryConstructorIfAbsent() +internal object AddDefaultConstructorFixFactory : KotlinSingleIntentionActionFactory() { + fun superTypeEntryToClass(typeEntry: KtSuperTypeListEntry, context: BindingContext): KtClass? { + val baseType = context[BindingContext.TYPE, typeEntry.typeReference] ?: return null + val baseClassDescriptor = baseType.constructor.declarationDescriptor as? ClassDescriptor ?: return null + if (!baseClassDescriptor.isExpect) return null + if (baseClassDescriptor.kind != ClassKind.CLASS) return null + return DescriptorToSourceUtils.descriptorToDeclaration(baseClassDescriptor) as? KtClass } - companion object : KotlinSingleIntentionActionFactory() { - fun superTypeEntryToClass(typeEntry: KtSuperTypeListEntry, context: BindingContext): KtClass? { - val baseType = context[BindingContext.TYPE, typeEntry.typeReference] ?: return null - val baseClassDescriptor = baseType.constructor.declarationDescriptor as? ClassDescriptor ?: return null - if (!baseClassDescriptor.isExpect) return null - if (baseClassDescriptor.kind != ClassKind.CLASS) return null - return DescriptorToSourceUtils.descriptorToDeclaration(baseClassDescriptor) as? KtClass - } + private fun annotationEntryToClass(entry: KtAnnotationEntry, context: BindingContext): KtClass? { + val descriptor = + context[BindingContext.ANNOTATION, entry]?.type?.constructor?.declarationDescriptor as? ClassDescriptor ?: return null + if (!descriptor.isExpect) return null + return DescriptorToSourceUtils.descriptorToDeclaration(descriptor) as? KtClass + } - private fun annotationEntryToClass(entry: KtAnnotationEntry, context: BindingContext): KtClass? { - val descriptor = - context[BindingContext.ANNOTATION, entry]?.type?.constructor?.declarationDescriptor as? ClassDescriptor ?: return null - if (!descriptor.isExpect) return null - return DescriptorToSourceUtils.descriptorToDeclaration(descriptor) as? KtClass - } - - override fun createAction(diagnostic: Diagnostic): IntentionAction? { - val element = diagnostic.psiElement - if (element is KtValueArgumentList && element.arguments.isNotEmpty()) return null - val parent = element.getParentOfTypes(true, KtClassOrObject::class.java, KtAnnotationEntry::class.java) ?: return null - val context by lazy { parent.analyze() } - val baseClass = when (parent) { - is KtClassOrObject -> parent.superTypeListEntries.asSequence().filterIsInstance().firstOrNull()?.let { - superTypeEntryToClass(it, context) - } - is KtAnnotationEntry -> annotationEntryToClass(parent, context) - else -> null - } ?: return null - return AddDefaultConstructorFix(baseClass).asIntention() - } + override fun createAction(diagnostic: Diagnostic): IntentionAction? { + val element = diagnostic.psiElement + if (element is KtValueArgumentList && element.arguments.isNotEmpty()) return null + val parent = element.getParentOfTypes(true, KtClassOrObject::class.java, KtAnnotationEntry::class.java) ?: return null + val context by lazy { parent.analyze() } + val baseClass = when (parent) { + is KtClassOrObject -> parent.superTypeListEntries.asSequence().filterIsInstance().firstOrNull()?.let { + superTypeEntryToClass(it, context) + } + is KtAnnotationEntry -> annotationEntryToClass(parent, context) + else -> null + } ?: return null + return AddDefaultConstructorFix(baseClass).asIntention() } } \ No newline at end of file diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt index 7ddce50c99e9..c04528eb2b3b 100644 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt +++ b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt @@ -661,7 +661,7 @@ class QuickFixRegistrar : QuickFixContributor { WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET.registerFactory(MoveReceiverAnnotationFix, AddAnnotationTargetFix) NO_CONSTRUCTOR.registerFactory(RemoveNoConstructorFixFactory) - NO_CONSTRUCTOR.registerFactory(AddDefaultConstructorFix) + NO_CONSTRUCTOR.registerFactory(AddDefaultConstructorFixFactory) NO_CONSTRUCTOR_WARNING.registerFactory(RemoveNoConstructorFixFactory) ANNOTATION_USED_AS_ANNOTATION_ARGUMENT.registerFactory(RemoveAtFromAnnotationArgument) diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/quickfix/SuperClassNotInitialized.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/quickfix/SuperClassNotInitialized.kt index 5fe92ebccbcc..f5f439b4c46c 100644 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/quickfix/SuperClassNotInitialized.kt +++ b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/quickfix/SuperClassNotInitialized.kt @@ -14,17 +14,16 @@ import com.intellij.psi.util.PsiTreeUtil import org.jetbrains.annotations.Nls import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.diagnostics.Diagnostic +import org.jetbrains.kotlin.idea.base.psi.replaced import org.jetbrains.kotlin.idea.base.resources.KotlinBundle import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny import org.jetbrains.kotlin.idea.caches.resolve.resolveToParameterDescriptorIfAny +import org.jetbrains.kotlin.idea.codeinsight.api.classic.quickfixes.KotlinQuickFixAction import org.jetbrains.kotlin.idea.core.ShortenReferences import org.jetbrains.kotlin.idea.core.isVisible import org.jetbrains.kotlin.idea.core.moveCaret -import org.jetbrains.kotlin.idea.base.psi.replaced -import org.jetbrains.kotlin.util.match -import org.jetbrains.kotlin.idea.codeinsight.api.classic.quickfixes.KotlinQuickFixAction import org.jetbrains.kotlin.idea.resolve.languageVersionSettings import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers import org.jetbrains.kotlin.idea.util.application.isUnitTestMode @@ -32,6 +31,7 @@ import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType import org.jetbrains.kotlin.psi.psiUtil.hasExpectModifier +import org.jetbrains.kotlin.psi.psiUtil.parents import org.jetbrains.kotlin.renderer.DescriptorRenderer import org.jetbrains.kotlin.renderer.render import org.jetbrains.kotlin.resolve.BindingContext @@ -42,8 +42,8 @@ import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeConstructorSubstitution import org.jetbrains.kotlin.types.isError import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf +import org.jetbrains.kotlin.util.match import org.jetbrains.kotlin.utils.addIfNotNull -import org.jetbrains.kotlin.psi.psiUtil.parents object SuperClassNotInitialized : KotlinIntentionActionsFactory() { private const val DISPLAY_MAX_PARAMS = 5 @@ -133,7 +133,7 @@ object SuperClassNotInitialized : KotlinIntentionActionsFactory() { override fun invoke(project: Project, editor: Editor?, file: KtFile) { val element = element ?: return val context = (element.getStrictParentOfType() ?: element).analyze() - val baseClass = AddDefaultConstructorFix.superTypeEntryToClass(element, context) + val baseClass = AddDefaultConstructorFixFactory.superTypeEntryToClass(element, context) val newSpecifier = element.replaced(KtPsiFactory(project).createSuperTypeCallEntry(element.text + "()")) if (baseClass != null && baseClass.hasExpectModifier() && baseClass.secondaryConstructors.isEmpty()) {