diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/AddActualFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/AddActualFix.kt index 2873fd6cfa4..05475264804 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/AddActualFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/AddActualFix.kt @@ -30,6 +30,7 @@ import org.jetbrains.kotlin.idea.core.ShortenReferences import org.jetbrains.kotlin.idea.core.toDescriptor import org.jetbrains.kotlin.idea.quickfix.KotlinQuickFixAction import org.jetbrains.kotlin.idea.quickfix.KotlinSingleIntentionActionFactory +import org.jetbrains.kotlin.idea.util.module import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.createSmartPointer import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils @@ -55,9 +56,10 @@ class AddActualFix( ShortenReferences.DEFAULT.process(codeStyleManager.reformat(this) as KtElement) } + val module = element.module ?: return for (missedDeclaration in missedDeclarationPointers.mapNotNull { it.element }) { val actualDeclaration = when (missedDeclaration) { - is KtClassOrObject -> factory.generateClassOrObject(project, false, missedDeclaration, outerClasses = listOf(element)) + is KtClassOrObject -> factory.generateClassOrObject(project, false, missedDeclaration, module, listOf(element)) is KtFunction -> missedDeclaration.toDescriptor()?.safeAs()?.let { generateFunction(project, false, missedDeclaration, it, element) } diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/CreateActualFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/CreateActualFix.kt index e1af24a98e4..233e1ce3d7e 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/CreateActualFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/CreateActualFix.kt @@ -30,9 +30,9 @@ import org.jetbrains.kotlin.idea.caches.project.ModuleSourceInfo import org.jetbrains.kotlin.idea.core.toDescriptor import org.jetbrains.kotlin.idea.quickfix.KotlinSingleIntentionActionFactory import org.jetbrains.kotlin.idea.util.actualsForExpected +import org.jetbrains.kotlin.platform.TargetPlatform import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.hasExpectModifier -import org.jetbrains.kotlin.platform.TargetPlatform sealed class CreateActualFix( declaration: D, @@ -87,7 +87,7 @@ class CreateActualClassFix( actualModule: Module, actualPlatform: TargetPlatform ) : CreateActualFix(klass, actualModule, actualPlatform, { project, element -> - generateClassOrObject(project, false, element) + generateClassOrObject(project, false, element, targetModule = actualModule) }) class CreateActualPropertyFix( diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/CreateExpectedFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/CreateExpectedFix.kt index ba35d2d607a..a244c8f9eed 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/CreateExpectedFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/CreateExpectedFix.kt @@ -36,6 +36,7 @@ import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject import org.jetbrains.kotlin.psi.psiUtil.createSmartPointer +import org.jetbrains.kotlin.psi.psiUtil.getSuperNames import org.jetbrains.kotlin.psi.psiUtil.hasActualModifier import org.jetbrains.kotlin.utils.addToStdlib.safeAs import java.util.* @@ -286,7 +287,16 @@ class CreateExpectedPropertyFix( return@block null } val descriptor = element.toDescriptor() as? PropertyDescriptor - descriptor?.let { generateProperty(project, true, element, descriptor, targetExpectedClass) } + descriptor?.let { + generateProperty( + project, + true, + element, + descriptor, + targetExpectedClass, + existingFqNames = targetExpectedClass?.getSuperNames().orEmpty() + ) + } }) class CreateExpectedFunctionFix( @@ -299,6 +309,15 @@ class CreateExpectedFunctionFix( return@block null } val descriptor = element.toDescriptor() as? FunctionDescriptor - descriptor?.let { generateFunction(project, true, element, descriptor, targetExpectedClass) } + descriptor?.let { + generateFunction( + project, + true, + element, + descriptor, + targetExpectedClass, + existingFqNames = targetExpectedClass?.getSuperNames().orEmpty() + ) + } }) diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/ExpectActualUtils.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/ExpectActualUtils.kt index f704d180b1d..5b9caf5e4f8 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/ExpectActualUtils.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/ExpectActualUtils.kt @@ -117,13 +117,13 @@ internal fun KtPsiFactory.generateClassOrObject( project: Project, generateExpectClass: Boolean, originalClass: KtClassOrObject, - targetModule: Module? = null, + targetModule: Module, outerClasses: List = emptyList(), existingFqNames: Set = emptySet() ): KtClassOrObject { val generatedClass = createClassHeaderCopyByText(originalClass) val context = originalClass.analyzeWithContent() - repairSuperTypeList( + val superNames = repairSuperTypeList( generatedClass, originalClass, generateExpectClass, @@ -179,7 +179,7 @@ internal fun KtPsiFactory.generateClassOrObject( descriptor as FunctionDescriptor, generatedClass, existingClasses, - existingFqNames + existingFqNames + superNames ) is KtProperty -> generateProperty( project, @@ -188,7 +188,7 @@ internal fun KtPsiFactory.generateClassOrObject( descriptor as PropertyDescriptor, generatedClass, existingClasses, - existingFqNames + existingFqNames + superNames ) else -> continue@declLoop } @@ -208,7 +208,7 @@ internal fun KtPsiFactory.generateClassOrObject( descriptor, generatedClass, outerClasses, - existingFqNames + existingFqNames + superNames ) generatedClass.addDeclaration(generatedProperty) } @@ -228,7 +228,7 @@ internal fun KtPsiFactory.generateClassOrObject( descriptor, generatedClass, outerClasses, - existingFqNames + existingFqNames + superNames ) generatedClass.createPrimaryConstructorIfAbsent().replace(expectedPrimaryConstructor) } @@ -245,7 +245,8 @@ private fun KtPsiFactory.repairSuperTypeList( targetModule: Module?, existingFqNames: Set, context: BindingContext -) { +): Collection { + val superNames = linkedSetOf() generated.superTypeListEntries.zip(original.superTypeListEntries).forEach { (generatedEntry, originalEntry) -> val superType = context[BindingContext.TYPE, originalEntry.typeReference] val superClassDescriptor = superType?.constructor?.declarationDescriptor as? ClassDescriptor ?: return@forEach @@ -257,6 +258,7 @@ private fun KtPsiFactory.repairSuperTypeList( return@forEach } + superType.fqName?.shortName()?.asString()?.let { superNames += it } if (generateExpectClass) { if (generatedEntry !is KtSuperTypeCallEntry) return@forEach } else { @@ -275,6 +277,7 @@ private fun KtPsiFactory.repairSuperTypeList( } if (generated.superTypeListEntries.isEmpty()) generated.getSuperTypeList()?.delete() + return superNames } private val forbiddenAnnotationFqNames = setOf( @@ -290,7 +293,7 @@ internal fun generateFunction( descriptor: FunctionDescriptor, generatedClass: KtClassOrObject? = null, outerClasses: List = emptyList(), - existingFqNames: Set = emptySet() + existingFqNames: Collection = emptySet() ): KtFunction { if (generateExpect) { val accessibleClasses = outerClasses + listOfNotNull(generatedClass) @@ -309,7 +312,7 @@ internal fun generateFunction( copyDoc = true, project = project, mode = if (generateExpect) MemberGenerateMode.EXPECT else MemberGenerateMode.ACTUAL - ) as KtFunction + ).also { if (generatedClass != null) it.repairOverride(descriptor, existingFqNames) } as KtFunction } internal fun generateProperty( @@ -319,7 +322,7 @@ internal fun generateProperty( descriptor: PropertyDescriptor, generatedClass: KtClassOrObject? = null, outerClasses: List = emptyList(), - existingFqNames: Set = emptySet() + existingFqNames: Collection = emptySet() ): KtProperty { if (generateExpect) { val accessibleClasses = outerClasses + listOfNotNull(generatedClass) @@ -335,7 +338,16 @@ internal fun generateProperty( copyDoc = true, project = project, mode = if (generateExpect) MemberGenerateMode.EXPECT else MemberGenerateMode.ACTUAL - ) as KtProperty + ).also { if (generatedClass != null) it.repairOverride(descriptor, existingFqNames) } as KtProperty +} + +private fun KtCallableDeclaration.repairOverride(descriptor: CallableDescriptor, existingFqNames: Collection) { + if (!hasModifier(KtTokens.OVERRIDE_KEYWORD)) return + + val superDescriptor = descriptor.overriddenDescriptors.firstOrNull()?.containingDeclaration + if (superDescriptor?.fqNameOrNull()?.shortName()?.asString() !in existingFqNames) { + removeModifier(KtTokens.OVERRIDE_KEYWORD) + } } private fun CallableMemberDescriptor.checkTypeParameterBoundsAccessibility(accessibleClasses: List) { @@ -427,11 +439,11 @@ private tailrec fun DeclarationDescriptor.additionalClasses(existingClasses: Set } private fun DeclarationDescriptor.collectAllTypes(): Sequence { - return sequenceOf(fqNameOrNull()) + when (this) { + return when (this) { is ClassConstructorDescriptor -> valueParameters.asSequence().map(ValueParameterDescriptor::getType).flatMap(KotlinType::collectAllTypes) is ClassDescriptor -> if (isInline) unsubstitutedPrimaryConstructor?.collectAllTypes().orEmpty() else { emptySequence() - } + declaredTypeParameters.asSequence().flatMap(DeclarationDescriptor::collectAllTypes) + } + declaredTypeParameters.asSequence().flatMap(DeclarationDescriptor::collectAllTypes) + sequenceOf(fqNameOrNull()) is CallableDescriptor -> { val returnType = returnType ?: return sequenceOf(null) returnType.collectAllTypes() + explicitParameters.asSequence().map(ParameterDescriptor::getType).flatMap(KotlinType::collectAllTypes)