ExpectActualUtils: should add annotations

This commit is contained in:
Dmitry Gridin
2019-08-08 19:02:09 +03:00
parent 5e60ea2272
commit 1748906d9a
4 changed files with 79 additions and 42 deletions
@@ -61,10 +61,10 @@ class AddActualFix(
val actualDeclaration = when (missedDeclaration) { val actualDeclaration = when (missedDeclaration) {
is KtClassOrObject -> factory.generateClassOrObject(project, false, missedDeclaration, module, listOf(element)) is KtClassOrObject -> factory.generateClassOrObject(project, false, missedDeclaration, module, listOf(element))
is KtFunction -> missedDeclaration.toDescriptor()?.safeAs<FunctionDescriptor>()?.let { is KtFunction -> missedDeclaration.toDescriptor()?.safeAs<FunctionDescriptor>()?.let {
generateFunction(project, false, missedDeclaration, it, element) generateFunction(project, false, missedDeclaration, it, element, targetModule = module)
} }
is KtProperty -> missedDeclaration.toDescriptor()?.safeAs<PropertyDescriptor>()?.let { is KtProperty -> missedDeclaration.toDescriptor()?.safeAs<PropertyDescriptor>()?.let {
generateProperty(project, false, missedDeclaration, it, element) generateProperty(project, false, missedDeclaration, it, element, targetModule = module)
} }
else -> null else -> null
} ?: continue } ?: continue
@@ -96,7 +96,7 @@ class CreateActualPropertyFix(
actualPlatform: TargetPlatform actualPlatform: TargetPlatform
) : CreateActualFix<KtProperty>(property, actualModule, actualPlatform, { project, element -> ) : CreateActualFix<KtProperty>(property, actualModule, actualPlatform, { project, element ->
val descriptor = element.toDescriptor() as? PropertyDescriptor val descriptor = element.toDescriptor() as? PropertyDescriptor
descriptor?.let { generateProperty(project, false, element, descriptor) } descriptor?.let { generateProperty(project, false, element, descriptor, targetModule = actualModule) }
}) })
class CreateActualFunctionFix( class CreateActualFunctionFix(
@@ -105,6 +105,6 @@ class CreateActualFunctionFix(
actualPlatform: TargetPlatform actualPlatform: TargetPlatform
) : CreateActualFix<KtFunction>(function, actualModule, actualPlatform, { project, element -> ) : CreateActualFix<KtFunction>(function, actualModule, actualPlatform, { project, element ->
val descriptor = element.toDescriptor() as? FunctionDescriptor val descriptor = element.toDescriptor() as? FunctionDescriptor
descriptor?.let { generateFunction(project, false, element, descriptor) } descriptor?.let { generateFunction(project, false, element, descriptor, targetModule = actualModule) }
}) })
@@ -294,7 +294,8 @@ class CreateExpectedPropertyFix(
element, element,
descriptor, descriptor,
targetExpectedClass, targetExpectedClass,
existingFqNames = targetExpectedClass?.getSuperNames().orEmpty() existingFqNames = targetExpectedClass?.getSuperNames()?.toSet().orEmpty(),
targetModule = commonModule
) )
} }
}) })
@@ -316,7 +317,8 @@ class CreateExpectedFunctionFix(
element, element,
descriptor, descriptor,
targetExpectedClass, targetExpectedClass,
existingFqNames = targetExpectedClass?.getSuperNames().orEmpty() existingFqNames = targetExpectedClass?.getSuperNames()?.toSet().orEmpty(),
targetModule = commonModule
) )
} }
}) })
@@ -11,6 +11,7 @@ import com.intellij.psi.JavaDirectoryService
import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.backend.common.descriptors.explicitParameters import org.jetbrains.kotlin.backend.common.descriptors.explicitParameters
import org.jetbrains.kotlin.descriptors.* 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.implementedDescriptors
import org.jetbrains.kotlin.idea.caches.project.isTestModule import org.jetbrains.kotlin.idea.caches.project.isTestModule
import org.jetbrains.kotlin.idea.caches.project.toDescriptor 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.fqNameOrNull
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.module 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.AbbreviatedType
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeProjection import org.jetbrains.kotlin.types.TypeProjection
@@ -133,14 +135,13 @@ internal fun KtPsiFactory.generateClassOrObject(
context context
) )
if (generatedClass.isAnnotation()) { generatedClass.annotationEntries.zip(originalClass.annotationEntries).forEach { (generatedEntry, originalEntry) ->
generatedClass.annotationEntries.zip(originalClass.annotationEntries).forEach { (generatedEntry, originalEntry) -> val annotationDescriptor = context.get(BindingContext.ANNOTATION, originalEntry)
val annotationDescriptor = context.get(BindingContext.ANNOTATION, originalEntry) ?: return@forEach if (annotationDescriptor?.isValidInModule(targetModule, existingFqNames, project) != true) {
if (annotationDescriptor.fqName in forbiddenAnnotationFqNames) { generatedEntry.delete()
generatedEntry.delete()
}
} }
} }
if (generateExpectClass) { if (generateExpectClass) {
if (outerClasses.isEmpty()) { if (outerClasses.isEmpty()) {
generatedClass.addModifier(KtTokens.EXPECT_KEYWORD) generatedClass.addModifier(KtTokens.EXPECT_KEYWORD)
@@ -170,29 +171,26 @@ internal fun KtPsiFactory.generateClassOrObject(
existingClasses, existingClasses,
existingFqNames existingFqNames
) )
is KtCallableDeclaration -> { is KtFunction -> generateFunction(
when (originalDeclaration) { project,
is KtFunction -> generateFunction( generateExpectClass,
project, originalDeclaration,
generateExpectClass, descriptor as FunctionDescriptor,
originalDeclaration, generatedClass,
descriptor as FunctionDescriptor, existingClasses,
generatedClass, existingFqNames + superNames,
existingClasses, targetModule
existingFqNames + superNames )
) is KtProperty -> generateProperty(
is KtProperty -> generateProperty( project,
project, generateExpectClass,
generateExpectClass, originalDeclaration,
originalDeclaration, descriptor as PropertyDescriptor,
descriptor as PropertyDescriptor, generatedClass,
generatedClass, existingClasses,
existingClasses, existingFqNames + superNames,
existingFqNames + superNames targetModule
) )
else -> continue@declLoop
}
}
else -> continue@declLoop else -> continue@declLoop
} }
generatedClass.addDeclaration(generatedDeclaration) generatedClass.addDeclaration(generatedDeclaration)
@@ -208,7 +206,8 @@ internal fun KtPsiFactory.generateClassOrObject(
descriptor, descriptor,
generatedClass, generatedClass,
outerClasses, outerClasses,
existingFqNames + superNames existingFqNames + superNames,
targetModule
) )
generatedClass.addDeclaration(generatedProperty) generatedClass.addDeclaration(generatedProperty)
} }
@@ -228,7 +227,8 @@ internal fun KtPsiFactory.generateClassOrObject(
descriptor, descriptor,
generatedClass, generatedClass,
outerClasses, outerClasses,
existingFqNames + superNames existingFqNames + superNames,
targetModule
) )
generatedClass.createPrimaryConstructorIfAbsent().replace(expectedPrimaryConstructor) generatedClass.createPrimaryConstructorIfAbsent().replace(expectedPrimaryConstructor)
} }
@@ -293,7 +293,8 @@ internal fun generateFunction(
descriptor: FunctionDescriptor, descriptor: FunctionDescriptor,
generatedClass: KtClassOrObject? = null, generatedClass: KtClassOrObject? = null,
outerClasses: List<KtClassOrObject> = emptyList(), outerClasses: List<KtClassOrObject> = emptyList(),
existingFqNames: Collection<String> = emptySet() existingFqNames: Set<String> = emptySet(),
targetModule: Module
): KtFunction { ): KtFunction {
if (generateExpect) { if (generateExpect) {
val accessibleClasses = outerClasses + listOfNotNull(generatedClass) val accessibleClasses = outerClasses + listOfNotNull(generatedClass)
@@ -312,7 +313,9 @@ internal fun generateFunction(
copyDoc = true, copyDoc = true,
project = project, project = project,
mode = if (generateExpect) MemberGenerateMode.EXPECT else MemberGenerateMode.ACTUAL 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( internal fun generateProperty(
@@ -322,7 +325,8 @@ internal fun generateProperty(
descriptor: PropertyDescriptor, descriptor: PropertyDescriptor,
generatedClass: KtClassOrObject? = null, generatedClass: KtClassOrObject? = null,
outerClasses: List<KtClassOrObject> = emptyList(), outerClasses: List<KtClassOrObject> = emptyList(),
existingFqNames: Collection<String> = emptySet() existingFqNames: Set<String> = emptySet(),
targetModule: Module
): KtProperty { ): KtProperty {
if (generateExpect) { if (generateExpect) {
val accessibleClasses = outerClasses + listOfNotNull(generatedClass) val accessibleClasses = outerClasses + listOfNotNull(generatedClass)
@@ -338,10 +342,23 @@ internal fun generateProperty(
copyDoc = true, copyDoc = true,
project = project, project = project,
mode = if (generateExpect) MemberGenerateMode.EXPECT else MemberGenerateMode.ACTUAL 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<String>) { private fun KtCallableDeclaration.repair(
generatedClass: KtClassOrObject?,
descriptor: CallableDescriptor,
existingFqNames: Set<String>,
targetModule: Module,
project: Project
) {
if (generatedClass != null) repairOverride(descriptor, existingFqNames)
repairAnnotationEntries(descriptor, existingFqNames, targetModule, project)
}
private fun KtCallableDeclaration.repairOverride(descriptor: CallableDescriptor, existingFqNames: Set<String>) {
if (!hasModifier(KtTokens.OVERRIDE_KEYWORD)) return if (!hasModifier(KtTokens.OVERRIDE_KEYWORD)) return
val superDescriptor = descriptor.overriddenDescriptors.firstOrNull()?.containingDeclaration val superDescriptor = descriptor.overriddenDescriptors.firstOrNull()?.containingDeclaration
@@ -350,6 +367,24 @@ private fun KtCallableDeclaration.repairOverride(descriptor: CallableDescriptor,
} }
} }
private fun KtCallableDeclaration.repairAnnotationEntries(
descriptor: CallableDescriptor,
existingFqNames: Set<String>,
module: Module,
project: Project
) {
for (annotation in descriptor.annotations) {
if (annotation.isValidInModule(module, existingFqNames, project)) {
val entry = annotation.source.safeAs<KotlinSourceElement>()?.psi.safeAs<KtAnnotationEntry>() ?: continue
addAnnotationEntry(entry)
}
}
}
private fun AnnotationDescriptor.isValidInModule(targetModule: Module, existingFqNames: Set<String>, project: Project): Boolean {
return fqName !in forbiddenAnnotationFqNames && type.checkTypeAccessibilityInModule(project, targetModule, existingFqNames)
}
private fun CallableMemberDescriptor.checkTypeParameterBoundsAccessibility(accessibleClasses: List<KtClassOrObject>) { private fun CallableMemberDescriptor.checkTypeParameterBoundsAccessibility(accessibleClasses: List<KtClassOrObject>) {
typeParameters.forEach { typeParameter -> typeParameters.forEach { typeParameter ->
typeParameter.upperBounds.forEach { upperBound -> typeParameter.upperBounds.forEach { upperBound ->