FIR type enhancements: support annotations for default parameter values

Related to KT-29937
This commit is contained in:
Mikhail Glukhikh
2019-03-07 14:05:53 +03:00
parent 5f3a01c25a
commit c708171add
23 changed files with 487 additions and 16 deletions
@@ -6,26 +6,35 @@
package org.jetbrains.kotlin.fir.java.enhancement
import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirCallableMember
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
import org.jetbrains.kotlin.fir.expressions.FirConstExpression
import org.jetbrains.kotlin.fir.expressions.resolvedFqName
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.impl.FirConstExpressionImpl
import org.jetbrains.kotlin.fir.expressions.impl.FirQualifiedAccessExpressionImpl
import org.jetbrains.kotlin.fir.java.createTypeParameterSymbol
import org.jetbrains.kotlin.fir.java.declarations.FirJavaClass
import org.jetbrains.kotlin.fir.java.declarations.FirJavaField
import org.jetbrains.kotlin.fir.java.toConeProjection
import org.jetbrains.kotlin.fir.java.toNotNullConeKotlinType
import org.jetbrains.kotlin.fir.java.types.FirJavaTypeRef
import org.jetbrains.kotlin.fir.references.FirResolvedCallableReferenceImpl
import org.jetbrains.kotlin.fir.references.FirSimpleNamedReference
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
import org.jetbrains.kotlin.fir.resolve.constructType
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.resolve.toTypeProjection
import org.jetbrains.kotlin.fir.service
import org.jetbrains.kotlin.fir.symbols.ConeCallableSymbol
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
import org.jetbrains.kotlin.fir.symbols.ConeClassifierSymbol
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
import org.jetbrains.kotlin.fir.typeContext
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.impl.FirResolvedTypeRefImpl
import org.jetbrains.kotlin.ir.expressions.IrConstKind
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
import org.jetbrains.kotlin.load.java.descriptors.AnnotationDefaultValue
import org.jetbrains.kotlin.load.java.descriptors.NullDefaultValue
@@ -34,9 +43,11 @@ import org.jetbrains.kotlin.load.java.structure.*
import org.jetbrains.kotlin.load.java.typeEnhancement.*
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.AbstractStrictEqualityTypeChecker
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import org.jetbrains.kotlin.utils.extractRadix
internal class IndexedJavaTypeQualifiers(private val data: Array<JavaTypeQualifiers>) {
constructor(size: Int, compute: (Int) -> JavaTypeQualifiers) : this(Array(size) { compute(it) })
@@ -220,7 +231,56 @@ internal fun FirTypeRef.typeArguments(): List<FirTypeProjection> =
internal fun JavaType.typeArguments(): List<JavaType?> = (this as? JavaClassifierType)?.typeArguments.orEmpty()
fun FirValueParameter.getDefaultValueFromAnnotation(): AnnotationDefaultValue? {
internal fun ConeKotlinType.lexicalCastFrom(session: FirSession, value: String): FirExpression? {
val lookupTagBasedType = when (this) {
is ConeLookupTagBasedType -> this
is ConeFlexibleType -> return lowerBound.lexicalCastFrom(session, value)
else -> return null
}
val lookupTag = lookupTagBasedType.lookupTag
val firElement = (lookupTag.toSymbol(session) as? FirBasedSymbol<*>)?.fir
if (firElement is FirRegularClass && firElement.classKind == ClassKind.ENUM_CLASS) {
val name = Name.identifier(value)
val firEnumEntry = firElement.declarations.filterIsInstance<FirEnumEntry>().find { it.name == name }
return if (firEnumEntry != null) FirQualifiedAccessExpressionImpl(session, null).apply {
calleeReference = FirSimpleNamedReference(
session, null, name // TODO: , firEnumEntry.symbol
)
} else if (firElement is FirJavaClass) {
val firStaticProperty = firElement.declarations.filterIsInstance<FirJavaField>().find {
it.isStatic && it.modality == Modality.FINAL && it.name == name
}
if (firStaticProperty != null) {
FirQualifiedAccessExpressionImpl(session, null).apply {
calleeReference = FirResolvedCallableReferenceImpl(
session, null, name, firStaticProperty.symbol as ConeCallableSymbol
)
}
} else null
} else null
}
if (lookupTag !is ConeClassLikeLookupTag) return null
val classId = lookupTag.classId
if (classId.packageFqName != FqName("kotlin")) return null
val (number, radix) = extractRadix(value)
return when (classId.relativeClassName.asString()) {
"Boolean" -> FirConstExpressionImpl(session, null, IrConstKind.Boolean, value.toBoolean())
"Char" -> FirConstExpressionImpl(session, null, IrConstKind.Char, value.singleOrNull() ?: return null)
"Byte" -> FirConstExpressionImpl(session, null, IrConstKind.Byte, number.toByteOrNull(radix) ?: return null)
"Short" -> FirConstExpressionImpl(session, null, IrConstKind.Short, number.toShortOrNull(radix) ?: return null)
"Int" -> FirConstExpressionImpl(session, null, IrConstKind.Int, number.toIntOrNull(radix) ?: return null)
"Long" -> FirConstExpressionImpl(session, null, IrConstKind.Long, number.toLongOrNull(radix) ?: return null)
"Float" -> FirConstExpressionImpl(session, null, IrConstKind.Float, value.toFloatOrNull() ?: return null)
"Double" -> FirConstExpressionImpl(session, null, IrConstKind.Double, value.toDoubleOrNull() ?: return null)
"String" -> FirConstExpressionImpl(session, null, IrConstKind.String, value)
else -> null
}
}
internal fun FirValueParameter.getDefaultValueFromAnnotation(): AnnotationDefaultValue? {
annotations.find { it.resolvedFqName == JvmAnnotationNames.DEFAULT_VALUE_FQ_NAME }
?.arguments?.firstOrNull()
?.safeAs<FirConstExpression<*>>()?.value?.safeAs<String>()
@@ -9,14 +9,14 @@ import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.impl.*
import org.jetbrains.kotlin.fir.expressions.FirAnnotationContainer
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.impl.FirConstExpressionImpl
import org.jetbrains.kotlin.fir.java.declarations.FirJavaConstructor
import org.jetbrains.kotlin.fir.java.declarations.FirJavaField
import org.jetbrains.kotlin.fir.java.declarations.FirJavaMethod
import org.jetbrains.kotlin.fir.java.declarations.FirJavaValueParameter
import org.jetbrains.kotlin.fir.java.enhancement.*
import org.jetbrains.kotlin.fir.java.enhancement.EnhancementSignatureParts
import org.jetbrains.kotlin.fir.java.enhancement.FirAnnotationTypeQualifierResolver
import org.jetbrains.kotlin.fir.java.enhancement.FirJavaEnhancementContext
import org.jetbrains.kotlin.fir.java.enhancement.copyWithNewDefaultTypeQualifiers
import org.jetbrains.kotlin.fir.java.types.FirJavaTypeRef
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
@@ -28,7 +28,10 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.ir.expressions.IrConstKind
import org.jetbrains.kotlin.load.java.AnnotationTypeQualifierResolver
import org.jetbrains.kotlin.load.java.descriptors.NullDefaultValue
import org.jetbrains.kotlin.load.java.descriptors.StringDefaultValue
import org.jetbrains.kotlin.load.java.structure.JavaPrimitiveType
import org.jetbrains.kotlin.load.java.typeEnhancement.PREDEFINED_FUNCTION_ENHANCEMENT_INFO_BY_SIGNATURE
import org.jetbrains.kotlin.load.java.typeEnhancement.PredefinedFunctionEnhancementInfo
@@ -130,10 +133,10 @@ class JavaClassEnhancementScope(
enhanceReturnType(firMethod, memberContext, predefinedEnhancementInfo)
}
val newValueParameterTypeRefs = mutableListOf<FirResolvedTypeRef>()
val newValueParameterInfo = mutableListOf<EnhanceValueParameterResult>()
for ((index, valueParameter) in firMethod.valueParameters.withIndex()) {
newValueParameterTypeRefs += enhanceValueParameterType(
newValueParameterInfo += enhanceValueParameter(
firMethod, memberContext, predefinedEnhancementInfo, valueParameter as FirJavaValueParameter, index
)
}
@@ -145,12 +148,13 @@ class JavaClassEnhancementScope(
).apply {
status = firMethod.status as FirDeclarationStatusImpl
annotations += firMethod.annotations
valueParameters += firMethod.valueParameters.zip(newValueParameterTypeRefs) { valueParameter, newTypeRef ->
valueParameters += firMethod.valueParameters.zip(newValueParameterInfo) { valueParameter, newInfo ->
val (newTypeRef, newDefaultValue) = newInfo
with(valueParameter) {
FirValueParameterImpl(
this@JavaClassEnhancementScope.session, psi,
this.name, newTypeRef,
defaultValue, isCrossinline, isNoinline, isVararg
defaultValue ?: newDefaultValue, isCrossinline, isNoinline, isVararg
).apply {
annotations += valueParameter.annotations
}
@@ -200,20 +204,29 @@ class JavaClassEnhancementScope(
return signatureParts.type
}
private fun enhanceValueParameterType(
private data class EnhanceValueParameterResult(val typeRef: FirResolvedTypeRef, val defaultValue: FirExpression?)
private fun enhanceValueParameter(
ownerFunction: FirCallableMember,
memberContext: FirJavaEnhancementContext,
predefinedEnhancementInfo: PredefinedFunctionEnhancementInfo?,
ownerParameter: FirJavaValueParameter,
index: Int
): FirResolvedTypeRef {
): EnhanceValueParameterResult {
val signatureParts = ownerFunction.partsForValueParameter(
typeQualifierResolver,
parameterContainer = ownerParameter,
methodContext = memberContext,
typeInSignature = TypeInSignature.ValueParameter(index)
).enhance(session, jsr305State, predefinedEnhancementInfo?.parametersInfo?.getOrNull(index))
return signatureParts.type
val firResolvedTypeRef = signatureParts.type
val defaultValue = ownerParameter.getDefaultValueFromAnnotation()
val defaultValueExpression = when (defaultValue) {
NullDefaultValue -> FirConstExpressionImpl(session, null, IrConstKind.Null, null)
is StringDefaultValue -> firResolvedTypeRef.type.lexicalCastFrom(session, defaultValue.value)
null -> null
}
return EnhanceValueParameterResult(firResolvedTypeRef, defaultValueExpression)
}
private fun enhanceReturnType(