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) {
is KtClassOrObject -> factory.generateClassOrObject(project, false, missedDeclaration, module, listOf(element))
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 {
generateProperty(project, false, missedDeclaration, it, element)
generateProperty(project, false, missedDeclaration, it, element, targetModule = module)
}
else -> null
} ?: continue
@@ -96,7 +96,7 @@ class CreateActualPropertyFix(
actualPlatform: TargetPlatform
) : CreateActualFix<KtProperty>(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<KtFunction>(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) }
})
@@ -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
)
}
})
@@ -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<KtClassOrObject> = emptyList(),
existingFqNames: Collection<String> = emptySet()
existingFqNames: Set<String> = 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<KtClassOrObject> = emptyList(),
existingFqNames: Collection<String> = emptySet()
existingFqNames: Set<String> = 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<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
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>) {
typeParameters.forEach { typeParameter ->
typeParameter.upperBounds.forEach { upperBound ->