[FIR] Support @kotlin.jvm.PurelyImplements annotation

This commit is contained in:
Dmitriy Novozhilov
2021-11-19 18:06:57 +03:00
parent 339c69fef0
commit 01c0cf80d0
5 changed files with 90 additions and 45 deletions
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.descriptors.EffectiveVisibility
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.analysis.checkers.typeParameterSymbols
import org.jetbrains.kotlin.fir.caches.createCache
import org.jetbrains.kotlin.fir.caches.firCachesFactory
import org.jetbrains.kotlin.fir.caches.getValue
@@ -25,15 +26,21 @@ import org.jetbrains.kotlin.fir.declarations.builder.buildTypeParameter
import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedDeclarationStatusImpl
import org.jetbrains.kotlin.fir.declarations.utils.effectiveVisibility
import org.jetbrains.kotlin.fir.declarations.utils.modality
import org.jetbrains.kotlin.fir.expressions.FirConstExpression
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.classId
import org.jetbrains.kotlin.fir.java.declarations.*
import org.jetbrains.kotlin.fir.java.enhancement.FirSignatureEnhancement
import org.jetbrains.kotlin.fir.resolve.constructType
import org.jetbrains.kotlin.fir.resolve.defaultType
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
import org.jetbrains.kotlin.load.java.FakePureImplementationsProvider
import org.jetbrains.kotlin.load.java.JavaClassFinder
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
import org.jetbrains.kotlin.load.java.structure.*
@@ -148,11 +155,54 @@ class FirJavaFacade(
firJavaClass.annotations.addFromJava(session, javaClass, javaTypeParameterStack)
val enhancement = FirSignatureEnhancement(firJavaClass, session) { emptyList() }
enhancement.enhanceTypeParameterBounds(firJavaClass.typeParameters)
firJavaClass.superTypeRefs.replaceAll { enhancement.enhanceSuperType(it) }
val enhancedSuperTypes = buildList {
val purelyImplementedSupertype = firJavaClass.getPurelyImplementedSupertype()
val purelyImplementedSupertypeClassId = purelyImplementedSupertype?.classId
firJavaClass.superTypeRefs.mapNotNullTo(this) { superType ->
enhancement.enhanceSuperType(superType).takeUnless {
purelyImplementedSupertypeClassId != null && it.coneType.classId == purelyImplementedSupertypeClassId
}
}
purelyImplementedSupertype?.let {
add(buildResolvedTypeRef { type = it })
}
}
firJavaClass.replaceSuperTypeRefs(enhancedSuperTypes)
firJavaClass.replaceDeprecation(firJavaClass.getDeprecationInfos(session.languageVersionSettings.apiVersion))
return firJavaClass
}
private fun FirJavaClass.getPurelyImplementedSupertype(): ConeKotlinType? {
val purelyImplementedClassIdFromAnnotation = annotations
.firstOrNull { it.classId?.asSingleFqName() == JvmAnnotationNames.PURELY_IMPLEMENTS_ANNOTATION }
?.let { (it.argumentMapping.mapping.values.firstOrNull() as? FirConstExpression<*>) }
?.let { it.value as? String }
?.takeIf { it.isNotBlank() && isValidJavaFqName(it) }
?.let { ClassId.topLevel(FqName(it)) }
val purelyImplementedClassId = purelyImplementedClassIdFromAnnotation
?: FakePureImplementationsProvider.getPurelyImplementedInterface(symbol.classId)
?: return null
val superTypeSymbol = session.symbolProvider.getClassLikeSymbolByClassId(purelyImplementedClassId) ?: return null
val superTypeParameterSymbols = superTypeSymbol.typeParameterSymbols ?: return null
val typeParameters = this.typeParameters
val supertypeParameterCount = superTypeParameterSymbols.size
val typeParameterCount = typeParameters.size
val parametersAsTypeProjections = when {
typeParameterCount == supertypeParameterCount ->
typeParameters.map { ConeTypeParameterTypeImpl(ConeTypeParameterLookupTag(it.symbol), isNullable = false) }
typeParameterCount == 1 && supertypeParameterCount > 1 && purelyImplementedClassIdFromAnnotation == null -> {
val projection = ConeTypeParameterTypeImpl(ConeTypeParameterLookupTag(typeParameters.first().symbol), isNullable = false)
(1..supertypeParameterCount).map { projection }
}
else -> return null
}
return ConeClassLikeTypeImpl(
ConeClassLikeLookupTagImpl(purelyImplementedClassId),
parametersAsTypeProjections.toTypedArray(),
isNullable = false
)
}
private fun createFirJavaClass(
javaClass: JavaClass,
classSymbol: FirRegularClassSymbol,