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 05475264804..380808cf4c7 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/AddActualFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/AddActualFix.kt @@ -61,10 +61,10 @@ class AddActualFix( val actualDeclaration = when (missedDeclaration) { is KtClassOrObject -> factory.generateClassOrObject(project, false, missedDeclaration, module, listOf(element)) is KtFunction -> missedDeclaration.toDescriptor()?.safeAs()?.let { - generateFunction(project, false, missedDeclaration, it, element) + generateFunction(project, false, missedDeclaration, it, element, targetModule = module) } is KtProperty -> missedDeclaration.toDescriptor()?.safeAs()?.let { - generateProperty(project, false, missedDeclaration, it, element) + generateProperty(project, false, missedDeclaration, it, element, targetModule = module) } else -> null } ?: continue 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 233e1ce3d7e..f31630c4437 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/CreateActualFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/CreateActualFix.kt @@ -96,7 +96,7 @@ class CreateActualPropertyFix( actualPlatform: TargetPlatform ) : CreateActualFix(property, actualModule, actualPlatform, { project, element -> val descriptor = element.toDescriptor() as? PropertyDescriptor - descriptor?.let { generateProperty(project, false, element, descriptor) } + descriptor?.let { generateProperty(project, false, element, descriptor, targetModule = actualModule) } }) class CreateActualFunctionFix( @@ -105,6 +105,6 @@ class CreateActualFunctionFix( actualPlatform: TargetPlatform ) : CreateActualFix(function, actualModule, actualPlatform, { project, element -> val descriptor = element.toDescriptor() as? FunctionDescriptor - descriptor?.let { generateFunction(project, false, element, descriptor) } + descriptor?.let { generateFunction(project, false, element, descriptor, targetModule = actualModule) } }) 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 a244c8f9eed..32722a2ec43 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/CreateExpectedFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/CreateExpectedFix.kt @@ -294,7 +294,8 @@ class CreateExpectedPropertyFix( element, descriptor, targetExpectedClass, - existingFqNames = targetExpectedClass?.getSuperNames().orEmpty() + existingFqNames = targetExpectedClass?.getSuperNames()?.toSet().orEmpty(), + targetModule = commonModule ) } }) @@ -316,7 +317,8 @@ class CreateExpectedFunctionFix( element, descriptor, targetExpectedClass, - existingFqNames = targetExpectedClass?.getSuperNames().orEmpty() + existingFqNames = targetExpectedClass?.getSuperNames()?.toSet().orEmpty(), + targetModule = commonModule ) } }) 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 5b9caf5e4f8..2a8610eca19 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/ExpectActualUtils.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/ExpectActualUtils.kt @@ -11,6 +11,7 @@ import com.intellij.psi.JavaDirectoryService import com.intellij.psi.search.GlobalSearchScope import org.jetbrains.kotlin.backend.common.descriptors.explicitParameters import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.idea.caches.project.implementedDescriptors import org.jetbrains.kotlin.idea.caches.project.isTestModule import org.jetbrains.kotlin.idea.caches.project.toDescriptor @@ -46,6 +47,7 @@ import org.jetbrains.kotlin.resolve.checkers.ExperimentalUsageChecker import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.descriptorUtil.module +import org.jetbrains.kotlin.resolve.source.KotlinSourceElement import org.jetbrains.kotlin.types.AbbreviatedType import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeProjection @@ -133,14 +135,13 @@ internal fun KtPsiFactory.generateClassOrObject( context ) - if (generatedClass.isAnnotation()) { - generatedClass.annotationEntries.zip(originalClass.annotationEntries).forEach { (generatedEntry, originalEntry) -> - val annotationDescriptor = context.get(BindingContext.ANNOTATION, originalEntry) ?: return@forEach - if (annotationDescriptor.fqName in forbiddenAnnotationFqNames) { - generatedEntry.delete() - } + generatedClass.annotationEntries.zip(originalClass.annotationEntries).forEach { (generatedEntry, originalEntry) -> + val annotationDescriptor = context.get(BindingContext.ANNOTATION, originalEntry) + if (annotationDescriptor?.isValidInModule(targetModule, existingFqNames, project) != true) { + generatedEntry.delete() } } + if (generateExpectClass) { if (outerClasses.isEmpty()) { generatedClass.addModifier(KtTokens.EXPECT_KEYWORD) @@ -170,29 +171,26 @@ internal fun KtPsiFactory.generateClassOrObject( existingClasses, existingFqNames ) - is KtCallableDeclaration -> { - when (originalDeclaration) { - is KtFunction -> generateFunction( - project, - generateExpectClass, - originalDeclaration, - descriptor as FunctionDescriptor, - generatedClass, - existingClasses, - existingFqNames + superNames - ) - is KtProperty -> generateProperty( - project, - generateExpectClass, - originalDeclaration, - descriptor as PropertyDescriptor, - generatedClass, - existingClasses, - existingFqNames + superNames - ) - else -> continue@declLoop - } - } + is KtFunction -> generateFunction( + project, + generateExpectClass, + originalDeclaration, + descriptor as FunctionDescriptor, + generatedClass, + existingClasses, + existingFqNames + superNames, + targetModule + ) + is KtProperty -> generateProperty( + project, + generateExpectClass, + originalDeclaration, + descriptor as PropertyDescriptor, + generatedClass, + existingClasses, + existingFqNames + superNames, + targetModule + ) else -> continue@declLoop } generatedClass.addDeclaration(generatedDeclaration) @@ -208,7 +206,8 @@ internal fun KtPsiFactory.generateClassOrObject( descriptor, generatedClass, outerClasses, - existingFqNames + superNames + existingFqNames + superNames, + targetModule ) generatedClass.addDeclaration(generatedProperty) } @@ -228,7 +227,8 @@ internal fun KtPsiFactory.generateClassOrObject( descriptor, generatedClass, outerClasses, - existingFqNames + superNames + existingFqNames + superNames, + targetModule ) generatedClass.createPrimaryConstructorIfAbsent().replace(expectedPrimaryConstructor) } @@ -293,7 +293,8 @@ internal fun generateFunction( descriptor: FunctionDescriptor, generatedClass: KtClassOrObject? = null, outerClasses: List = emptyList(), - existingFqNames: Collection = emptySet() + existingFqNames: Set = emptySet(), + targetModule: Module ): KtFunction { if (generateExpect) { val accessibleClasses = outerClasses + listOfNotNull(generatedClass) @@ -312,7 +313,9 @@ internal fun generateFunction( copyDoc = true, project = project, mode = if (generateExpect) MemberGenerateMode.EXPECT else MemberGenerateMode.ACTUAL - ).also { if (generatedClass != null) it.repairOverride(descriptor, existingFqNames) } as KtFunction + ).apply { + repair(generatedClass, descriptor, existingFqNames, targetModule, project) + } as KtFunction } internal fun generateProperty( @@ -322,7 +325,8 @@ internal fun generateProperty( descriptor: PropertyDescriptor, generatedClass: KtClassOrObject? = null, outerClasses: List = emptyList(), - existingFqNames: Collection = emptySet() + existingFqNames: Set = emptySet(), + targetModule: Module ): KtProperty { if (generateExpect) { val accessibleClasses = outerClasses + listOfNotNull(generatedClass) @@ -338,10 +342,23 @@ internal fun generateProperty( copyDoc = true, project = project, mode = if (generateExpect) MemberGenerateMode.EXPECT else MemberGenerateMode.ACTUAL - ).also { if (generatedClass != null) it.repairOverride(descriptor, existingFqNames) } as KtProperty + ).apply { + repair(generatedClass, descriptor, existingFqNames, targetModule, project) + } as KtProperty } -private fun KtCallableDeclaration.repairOverride(descriptor: CallableDescriptor, existingFqNames: Collection) { +private fun KtCallableDeclaration.repair( + generatedClass: KtClassOrObject?, + descriptor: CallableDescriptor, + existingFqNames: Set, + targetModule: Module, + project: Project +) { + if (generatedClass != null) repairOverride(descriptor, existingFqNames) + repairAnnotationEntries(descriptor, existingFqNames, targetModule, project) +} + +private fun KtCallableDeclaration.repairOverride(descriptor: CallableDescriptor, existingFqNames: Set) { if (!hasModifier(KtTokens.OVERRIDE_KEYWORD)) return val superDescriptor = descriptor.overriddenDescriptors.firstOrNull()?.containingDeclaration @@ -350,6 +367,24 @@ private fun KtCallableDeclaration.repairOverride(descriptor: CallableDescriptor, } } +private fun KtCallableDeclaration.repairAnnotationEntries( + descriptor: CallableDescriptor, + existingFqNames: Set, + module: Module, + project: Project +) { + for (annotation in descriptor.annotations) { + if (annotation.isValidInModule(module, existingFqNames, project)) { + val entry = annotation.source.safeAs()?.psi.safeAs() ?: continue + addAnnotationEntry(entry) + } + } +} + +private fun AnnotationDescriptor.isValidInModule(targetModule: Module, existingFqNames: Set, project: Project): Boolean { + return fqName !in forbiddenAnnotationFqNames && type.checkTypeAccessibilityInModule(project, targetModule, existingFqNames) +} + private fun CallableMemberDescriptor.checkTypeParameterBoundsAccessibility(accessibleClasses: List) { typeParameters.forEach { typeParameter -> typeParameter.upperBounds.forEach { upperBound ->