Introduce initial version of FIR Java type enhancement
Java type enhancement is performed by a special scope kind Java FIR dump was added for multiplatform tests to look at enhancements Overrides, J2K mapping, special cases does not work yet Related to KT-29937
This commit is contained in:
@@ -65,6 +65,10 @@ sealed class ConeKotlinType : ConeKotlinTypeProjection(), ConeTypedProjection, K
|
||||
abstract val nullability: ConeNullability
|
||||
}
|
||||
|
||||
val ConeKotlinType.isNullable: Boolean get() = nullability != ConeNullability.NOT_NULL
|
||||
|
||||
val ConeKotlinType.isMarkedNullable: Boolean get() = nullability == ConeNullability.NULLABLE
|
||||
|
||||
class ConeKotlinErrorType(val reason: String) : ConeKotlinType() {
|
||||
override val typeArguments: Array<out ConeKotlinTypeProjection>
|
||||
get() = EMPTY_ARRAY
|
||||
|
||||
@@ -9,11 +9,11 @@ import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import org.jetbrains.kotlin.analyzer.ModuleInfo
|
||||
import org.jetbrains.kotlin.fir.*
|
||||
import org.jetbrains.kotlin.fir.java.scopes.JavaFirScopeProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.FirProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.FirScopeProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.impl.FirCompositeSymbolProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.impl.FirDependenciesSymbolProviderImpl
|
||||
import org.jetbrains.kotlin.fir.resolve.impl.FirLibrarySymbolProviderImpl
|
||||
import org.jetbrains.kotlin.fir.resolve.impl.*
|
||||
|
||||
class FirJavaModuleBasedSession(
|
||||
moduleInfo: ModuleInfo,
|
||||
@@ -21,7 +21,6 @@ class FirJavaModuleBasedSession(
|
||||
scope: GlobalSearchScope,
|
||||
dependenciesProvider: FirSymbolProvider? = null
|
||||
) : FirModuleBasedSession(moduleInfo) {
|
||||
|
||||
init {
|
||||
sessionProvider.sessionCache[moduleInfo] = this
|
||||
registerComponent(
|
||||
@@ -35,6 +34,15 @@ class FirJavaModuleBasedSession(
|
||||
)
|
||||
)
|
||||
)
|
||||
registerComponent(
|
||||
FirScopeProvider::class,
|
||||
FirCompositeScopeProvider(
|
||||
listOf(
|
||||
JavaFirScopeProvider(),
|
||||
FirRegularScopeProvider()
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,6 +63,15 @@ class FirLibrarySession(
|
||||
)
|
||||
)
|
||||
)
|
||||
registerComponent(
|
||||
FirScopeProvider::class,
|
||||
FirCompositeScopeProvider(
|
||||
listOf(
|
||||
JavaFirScopeProvider(),
|
||||
FirRegularScopeProvider()
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,37 +9,23 @@ import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirNamedFunction
|
||||
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||
import org.jetbrains.kotlin.fir.declarations.impl.FirModifiableClass
|
||||
import org.jetbrains.kotlin.fir.declarations.impl.FirTypeParameterImpl
|
||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
|
||||
import org.jetbrains.kotlin.fir.expressions.FirArrayOfCall
|
||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.impl.*
|
||||
import org.jetbrains.kotlin.fir.java.declarations.FirJavaClass
|
||||
import org.jetbrains.kotlin.fir.java.declarations.FirJavaMethod
|
||||
import org.jetbrains.kotlin.fir.java.declarations.FirJavaValueParameter
|
||||
import org.jetbrains.kotlin.fir.java.types.FirJavaTypeRef
|
||||
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
|
||||
import org.jetbrains.kotlin.fir.references.FirResolvedCallableReferenceImpl
|
||||
import org.jetbrains.kotlin.fir.resolve.AbstractFirSymbolProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
|
||||
import org.jetbrains.kotlin.fir.service
|
||||
import org.jetbrains.kotlin.fir.symbols.*
|
||||
import org.jetbrains.kotlin.fir.symbols.CallableId
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeClassTypeImpl
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
|
||||
import org.jetbrains.kotlin.fir.types.impl.FirResolvedTypeRefImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.IrConstKind
|
||||
import org.jetbrains.kotlin.load.java.JavaClassFinder
|
||||
import org.jetbrains.kotlin.load.java.structure.*
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaClass
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.jvm.KotlinJavaPsiFacade
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
|
||||
class JavaSymbolProvider(
|
||||
val session: FirSession,
|
||||
@@ -49,149 +35,6 @@ class JavaSymbolProvider(
|
||||
|
||||
private val facade: KotlinJavaPsiFacade get() = KotlinJavaPsiFacade.getInstance(project)
|
||||
|
||||
private fun JavaAnnotation.toFirAnnotationCall(): FirAnnotationCall {
|
||||
return FirAnnotationCallImpl(
|
||||
session, psi = null, useSiteTarget = null,
|
||||
annotationTypeRef = FirResolvedTypeRefImpl(
|
||||
session = session,
|
||||
psi = null,
|
||||
type = ConeClassTypeImpl(FirClassSymbol(classId!!).toLookupTag(), emptyArray(), isNullable = false),
|
||||
isMarkedNullable = true,
|
||||
annotations = emptyList()
|
||||
)
|
||||
).apply {
|
||||
for (argument in this@toFirAnnotationCall.arguments) {
|
||||
arguments += argument.toFirExpression()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: use kind here
|
||||
private fun <T> List<T>.createArrayOfCall(@Suppress("UNUSED_PARAMETER") kind: IrConstKind<T>): FirArrayOfCall {
|
||||
return FirArrayOfCallImpl(session, null).apply {
|
||||
for (element in this@createArrayOfCall) {
|
||||
arguments += element.createConstant()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun Any?.createConstant(): FirExpression {
|
||||
return when (this) {
|
||||
is Byte -> FirConstExpressionImpl(session, null, IrConstKind.Byte, this)
|
||||
is Short -> FirConstExpressionImpl(session, null, IrConstKind.Short, this)
|
||||
is Int -> FirConstExpressionImpl(session, null, IrConstKind.Int, this)
|
||||
is Long -> FirConstExpressionImpl(session, null, IrConstKind.Long, this)
|
||||
is Char -> FirConstExpressionImpl(session, null, IrConstKind.Char, this)
|
||||
is Float -> FirConstExpressionImpl(session, null, IrConstKind.Float, this)
|
||||
is Double -> FirConstExpressionImpl(session, null, IrConstKind.Double, this)
|
||||
is Boolean -> FirConstExpressionImpl(session, null, IrConstKind.Boolean, this)
|
||||
is String -> FirConstExpressionImpl(session, null, IrConstKind.String, this)
|
||||
null -> FirConstExpressionImpl(session, null, IrConstKind.Null, null)
|
||||
|
||||
else -> FirErrorExpressionImpl(session, null, "Unknown value in JavaLiteralAnnotationArgument: $this")
|
||||
}
|
||||
}
|
||||
|
||||
private fun JavaAnnotationArgument.toFirExpression(): FirExpression {
|
||||
// TODO: this.name
|
||||
return when (this) {
|
||||
is JavaLiteralAnnotationArgument -> {
|
||||
when (val value = value) {
|
||||
is ByteArray -> value.toList().createArrayOfCall(IrConstKind.Byte)
|
||||
is ShortArray -> value.toList().createArrayOfCall(IrConstKind.Short)
|
||||
is IntArray -> value.toList().createArrayOfCall(IrConstKind.Int)
|
||||
is LongArray -> value.toList().createArrayOfCall(IrConstKind.Long)
|
||||
is CharArray -> value.toList().createArrayOfCall(IrConstKind.Char)
|
||||
is FloatArray -> value.toList().createArrayOfCall(IrConstKind.Float)
|
||||
is DoubleArray -> value.toList().createArrayOfCall(IrConstKind.Double)
|
||||
is BooleanArray -> value.toList().createArrayOfCall(IrConstKind.Boolean)
|
||||
else -> value.createConstant()
|
||||
}
|
||||
}
|
||||
is JavaArrayAnnotationArgument -> FirArrayOfCallImpl(session, null).apply {
|
||||
for (element in getElements()) {
|
||||
arguments += element.toFirExpression()
|
||||
}
|
||||
}
|
||||
is JavaEnumValueAnnotationArgument -> {
|
||||
FirFunctionCallImpl(session, null).apply {
|
||||
val classId = this@toFirExpression.enumClassId
|
||||
val entryName = this@toFirExpression.entryName
|
||||
val calleeReference = if (classId != null && entryName != null) {
|
||||
val callableSymbol = session.service<FirSymbolProvider>().getCallableSymbols(
|
||||
CallableId(classId.packageFqName, classId.relativeClassName, entryName)
|
||||
).firstOrNull()
|
||||
callableSymbol?.let {
|
||||
FirResolvedCallableReferenceImpl(session, null, entryName, it)
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
this.calleeReference = calleeReference
|
||||
?: FirErrorNamedReference(session, null, "Strange Java enum value: ${this@toFirExpression}")
|
||||
}
|
||||
}
|
||||
is JavaClassObjectAnnotationArgument -> FirGetClassCallImpl(session, null).apply {
|
||||
val referencedType = getReferencedType()
|
||||
arguments += FirClassReferenceExpressionImpl(session, null, referencedType.toFirResolvedTypeRef())
|
||||
}
|
||||
is JavaAnnotationAsAnnotationArgument -> getAnnotation().toFirAnnotationCall()
|
||||
else -> FirErrorExpressionImpl(session, null, "Unknown JavaAnnotationArgument: ${this::class.java}")
|
||||
}
|
||||
}
|
||||
|
||||
private fun JavaClassifierType.toFirResolvedTypeRef(): FirResolvedTypeRef {
|
||||
val coneType = when (val classifier = classifier) {
|
||||
is JavaClass -> {
|
||||
val lookupTag = ConeClassLikeLookupTagImpl(classifier.classId!!)
|
||||
ConeClassTypeImpl(lookupTag, typeArguments.map { it.toConeProjection() }.toTypedArray(), isNullable = false)
|
||||
}
|
||||
is JavaTypeParameter -> {
|
||||
// TODO: it's unclear how to identify type parameter by the symbol
|
||||
// TODO: some type parameter cache (provider?)
|
||||
val symbol = createTypeParameterSymbol(classifier.name)
|
||||
ConeTypeParameterTypeImpl(symbol, isNullable = false)
|
||||
}
|
||||
else -> ConeClassErrorType(reason = "Unexpected classifier: $classifier")
|
||||
}
|
||||
return FirResolvedTypeRefImpl(
|
||||
session, psi = null, type = coneType,
|
||||
isMarkedNullable = false, annotations = annotations.map { it.toFirAnnotationCall() }
|
||||
)
|
||||
}
|
||||
|
||||
private fun JavaType.toFirJavaTypeRef(): FirJavaTypeRef {
|
||||
val annotations = (this as? JavaClassifierType)?.annotations.orEmpty()
|
||||
return FirJavaTypeRef(session, annotations = annotations.map { it.toFirAnnotationCall() }, type = this)
|
||||
}
|
||||
|
||||
private fun JavaType.toFirResolvedTypeRef(): FirResolvedTypeRef {
|
||||
if (this is JavaClassifierType) return toFirResolvedTypeRef()
|
||||
return FirResolvedTypeRefImpl(
|
||||
session, psi = null, type = ConeClassErrorType("Unexpected JavaType: $this"),
|
||||
isMarkedNullable = false, annotations = emptyList()
|
||||
)
|
||||
}
|
||||
|
||||
private fun JavaType.toConeProjection(): ConeKotlinTypeProjection {
|
||||
if (this is JavaClassifierType) {
|
||||
return toFirResolvedTypeRef().type
|
||||
}
|
||||
return ConeClassErrorType("Unexpected type argument: $this")
|
||||
}
|
||||
|
||||
private fun createTypeParameterSymbol(name: Name): FirTypeParameterSymbol {
|
||||
val firSymbol = FirTypeParameterSymbol()
|
||||
FirTypeParameterImpl(session, null, firSymbol, name, variance = Variance.INVARIANT, isReified = false)
|
||||
return firSymbol
|
||||
}
|
||||
|
||||
private fun FirAbstractAnnotatedElement.addAnnotationsFrom(javaAnnotationOwner: JavaAnnotationOwner) {
|
||||
for (annotation in javaAnnotationOwner.annotations) {
|
||||
annotations += annotation.toFirAnnotationCall()
|
||||
}
|
||||
}
|
||||
|
||||
private fun findClass(classId: ClassId): JavaClass? = facade.findClass(JavaClassFinder.Request(classId), searchScope)
|
||||
|
||||
override fun getCallableSymbols(callableId: CallableId): List<ConeCallableSymbol> {
|
||||
@@ -201,39 +44,12 @@ class JavaSymbolProvider(
|
||||
?: return@lookupCacheOrCalculate emptyList()
|
||||
val firClass = classSymbol.fir as FirModifiableClass
|
||||
val callableSymbols = mutableListOf<ConeCallableSymbol>()
|
||||
findClass(classId)?.let { javaClass ->
|
||||
if (firClass.declarations.isEmpty()) {
|
||||
for (javaMethod in javaClass.methods) {
|
||||
val methodName = javaMethod.name
|
||||
val methodId = CallableId(callableId.packageName, callableId.className, methodName)
|
||||
val methodSymbol = FirFunctionSymbol(methodId)
|
||||
val memberFunction = FirJavaMethod(
|
||||
session, methodSymbol, methodName,
|
||||
javaMethod.visibility, javaMethod.modality,
|
||||
returnTypeRef = javaMethod.returnType.toFirJavaTypeRef()
|
||||
).apply {
|
||||
for (typeParameter in javaMethod.typeParameters) {
|
||||
typeParameters += createTypeParameterSymbol(typeParameter.name).fir
|
||||
}
|
||||
addAnnotationsFrom(javaMethod)
|
||||
for (valueParameter in javaMethod.valueParameters) {
|
||||
valueParameters += FirJavaValueParameter(
|
||||
session, valueParameter.name ?: Name.special("<anonymous Java parameter>"),
|
||||
returnTypeRef = valueParameter.type.toFirJavaTypeRef(),
|
||||
isVararg = valueParameter.isVararg
|
||||
)
|
||||
}
|
||||
}
|
||||
firClass.declarations += memberFunction
|
||||
}
|
||||
}
|
||||
for (declaration in firClass.declarations) {
|
||||
if (declaration is FirNamedFunction) {
|
||||
val methodId = CallableId(callableId.packageName, callableId.className, declaration.name)
|
||||
if (methodId == callableId) {
|
||||
val symbol = declaration.symbol as ConeCallableSymbol
|
||||
callableSymbols += symbol
|
||||
}
|
||||
for (declaration in firClass.declarations) {
|
||||
if (declaration is FirNamedFunction) {
|
||||
val methodId = CallableId(callableId.packageName, callableId.className, declaration.name)
|
||||
if (methodId == callableId) {
|
||||
val symbol = declaration.symbol as ConeCallableSymbol
|
||||
callableSymbols += symbol
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -254,14 +70,46 @@ class JavaSymbolProvider(
|
||||
FirJavaClass(
|
||||
session, firSymbol as FirClassSymbol, javaClass.name,
|
||||
javaClass.visibility, javaClass.modality,
|
||||
javaClass.classKind, javaClass.isStatic
|
||||
javaClass.classKind,
|
||||
isTopLevel = classId.relativeClassName.parent().isRoot, isStatic = javaClass.isStatic
|
||||
).apply {
|
||||
for (typeParameter in javaClass.typeParameters) {
|
||||
typeParameters += createTypeParameterSymbol(typeParameter.name).fir
|
||||
typeParameters += createTypeParameterSymbol(session, typeParameter.name).fir
|
||||
}
|
||||
addAnnotationsFrom(javaClass)
|
||||
for (supertype in javaClass.supertypes) {
|
||||
superTypeRefs += supertype.toFirResolvedTypeRef()
|
||||
superTypeRefs += supertype.toFirResolvedTypeRef(session)
|
||||
}
|
||||
// TODO: fields
|
||||
// TODO: may be we can process methods later.
|
||||
// However, they should be built up to override resolve stage
|
||||
for (javaMethod in javaClass.methods) {
|
||||
if (javaMethod.isStatic) continue // TODO: statics
|
||||
val methodName = javaMethod.name
|
||||
val methodId = CallableId(classId.packageFqName, classId.relativeClassName, methodName)
|
||||
val methodSymbol = FirFunctionSymbol(methodId)
|
||||
val returnType = javaMethod.returnType
|
||||
val firJavaMethod = FirJavaMethod(
|
||||
session, methodSymbol, methodName,
|
||||
javaMethod.visibility, javaMethod.modality,
|
||||
returnTypeRef = returnType.toFirJavaTypeRef(session)
|
||||
).apply {
|
||||
for (typeParameter in javaMethod.typeParameters) {
|
||||
typeParameters += createTypeParameterSymbol(session, typeParameter.name).fir
|
||||
}
|
||||
addAnnotationsFrom(javaMethod)
|
||||
for (valueParameter in javaMethod.valueParameters) {
|
||||
val parameterType = valueParameter.type
|
||||
valueParameters += FirJavaValueParameter(
|
||||
session, valueParameter.name ?: Name.special("<anonymous Java parameter>"),
|
||||
returnTypeRef = parameterType.toFirJavaTypeRef(session),
|
||||
isVararg = valueParameter.isVararg
|
||||
).apply {
|
||||
addAnnotationsFrom(valueParameter)
|
||||
}
|
||||
}
|
||||
}
|
||||
declarations += firJavaMethod
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -275,5 +123,12 @@ class JavaSymbolProvider(
|
||||
FqName(javaPackage.qualifiedName)
|
||||
}
|
||||
}
|
||||
|
||||
fun getJavaTopLevelClasses(): List<FirRegularClass> {
|
||||
return classCache.values
|
||||
.filterIsInstance<FirClassSymbol>()
|
||||
.filter { it.classId.relativeClassName.parent().isRoot }
|
||||
.map { it.fir }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,8 +7,31 @@ package org.jetbrains.kotlin.fir.java
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaClass
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaModifierListOwner
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.impl.FirTypeParameterImpl
|
||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
|
||||
import org.jetbrains.kotlin.fir.expressions.FirArrayOfCall
|
||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.impl.*
|
||||
import org.jetbrains.kotlin.fir.java.types.FirJavaTypeRef
|
||||
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
|
||||
import org.jetbrains.kotlin.fir.references.FirResolvedCallableReferenceImpl
|
||||
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
|
||||
import org.jetbrains.kotlin.fir.service
|
||||
import org.jetbrains.kotlin.fir.symbols.CallableId
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTagImpl
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeClassTypeImpl
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
|
||||
import org.jetbrains.kotlin.fir.types.impl.FirResolvedTypeRefImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.IrConstKind
|
||||
import org.jetbrains.kotlin.load.java.structure.*
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
|
||||
internal val JavaModifierListOwner.modality: Modality
|
||||
get() = when {
|
||||
@@ -24,3 +47,210 @@ internal val JavaClass.classKind: ClassKind
|
||||
isEnum -> ClassKind.ENUM_CLASS
|
||||
else -> ClassKind.CLASS
|
||||
}
|
||||
|
||||
internal fun ClassId.toConeKotlinType(
|
||||
typeArguments: Array<ConeKotlinTypeProjection>,
|
||||
isNullable: Boolean
|
||||
): ConeLookupTagBasedType {
|
||||
val lookupTag = ConeClassLikeLookupTagImpl(this)
|
||||
return ConeClassTypeImpl(lookupTag, typeArguments, isNullable)
|
||||
}
|
||||
|
||||
internal fun FirTypeRef.toNotNullConeKotlinType(): ConeKotlinType =
|
||||
when (this) {
|
||||
is FirResolvedTypeRef -> type
|
||||
is FirJavaTypeRef -> {
|
||||
val javaType = type
|
||||
javaType.toNotNullConeKotlinType(session)
|
||||
}
|
||||
else -> ConeKotlinErrorType("Unexpected type reference in JavaClassUseSiteScope: ${this::class.java}")
|
||||
}
|
||||
|
||||
internal fun JavaType.toNotNullConeKotlinType(session: FirSession): ConeLookupTagBasedType {
|
||||
return toConeKotlinTypeWithNullability(session, isNullable = false)
|
||||
}
|
||||
|
||||
internal fun JavaType.toFirJavaTypeRef(session: FirSession): FirJavaTypeRef {
|
||||
val annotations = (this as? JavaClassifierType)?.annotations.orEmpty()
|
||||
return FirJavaTypeRef(session, annotations = annotations.map { it.toFirAnnotationCall(session) }, type = this)
|
||||
}
|
||||
|
||||
internal fun JavaClassifierType.toFirResolvedTypeRef(session: FirSession): FirResolvedTypeRef {
|
||||
val coneType = this.toConeKotlinTypeWithNullability(session, isNullable = false)
|
||||
return FirResolvedTypeRefImpl(
|
||||
session, psi = null, type = coneType,
|
||||
isMarkedNullable = false, annotations = annotations.map { it.toFirAnnotationCall(session) }
|
||||
)
|
||||
}
|
||||
|
||||
internal fun JavaType.toConeKotlinTypeWithNullability(session: FirSession, isNullable: Boolean): ConeLookupTagBasedType {
|
||||
return when (this) {
|
||||
is JavaClassifierType -> {
|
||||
toConeKotlinTypeWithNullability(session, isNullable)
|
||||
}
|
||||
is JavaPrimitiveType -> {
|
||||
val primitiveType = type
|
||||
val kotlinPrimitiveName = when (val javaName = primitiveType?.typeName?.asString()) {
|
||||
null -> "Unit"
|
||||
else -> javaName.capitalize()
|
||||
}
|
||||
val classId = ClassId(FqName("kotlin"), FqName(kotlinPrimitiveName), false)
|
||||
classId.toConeKotlinType(emptyArray(), isNullable)
|
||||
}
|
||||
is JavaArrayType -> {
|
||||
val componentType = componentType
|
||||
if (componentType !is JavaPrimitiveType) {
|
||||
val classId = ClassId(FqName("kotlin"), FqName("Array"), false)
|
||||
val argumentType = ConeFlexibleType(
|
||||
componentType.toConeKotlinTypeWithNullability(session, isNullable = false),
|
||||
componentType.toConeKotlinTypeWithNullability(session, isNullable = true)
|
||||
)
|
||||
classId.toConeKotlinType(arrayOf(argumentType), isNullable)
|
||||
} else {
|
||||
val javaComponentName = componentType.type?.typeName?.asString()?.capitalize() ?: error("Array of voids")
|
||||
val classId = ClassId(FqName("kotlin"), FqName(javaComponentName + "Array"), false)
|
||||
classId.toConeKotlinType(emptyArray(), isNullable)
|
||||
}
|
||||
}
|
||||
is JavaWildcardType -> bound?.toNotNullConeKotlinType(session) ?: run {
|
||||
val classId = ClassId(FqName("kotlin"), FqName("Any"), false)
|
||||
classId.toConeKotlinType(emptyArray(), isNullable)
|
||||
}
|
||||
else -> error("Strange JavaType: ${this::class.java}")
|
||||
}
|
||||
}
|
||||
|
||||
internal fun JavaClassifierType.toConeKotlinTypeWithNullability(session: FirSession, isNullable: Boolean): ConeLookupTagBasedType {
|
||||
return when (val classifier = classifier) {
|
||||
is JavaClass -> {
|
||||
classifier.classId!!.toConeKotlinType(typeArguments.map { it.toConeProjection(session) }.toTypedArray(), isNullable)
|
||||
}
|
||||
is JavaTypeParameter -> {
|
||||
// TODO: it's unclear how to identify type parameter by the symbol
|
||||
// TODO: some type parameter cache (provider?)
|
||||
val symbol = createTypeParameterSymbol(session, classifier.name)
|
||||
ConeTypeParameterTypeImpl(symbol, isNullable)
|
||||
}
|
||||
else -> ConeClassErrorType(reason = "Unexpected classifier: $classifier")
|
||||
}
|
||||
}
|
||||
|
||||
internal fun createTypeParameterSymbol(session: FirSession, name: Name): FirTypeParameterSymbol {
|
||||
val firSymbol = FirTypeParameterSymbol()
|
||||
FirTypeParameterImpl(session, null, firSymbol, name, variance = Variance.INVARIANT, isReified = false)
|
||||
return firSymbol
|
||||
}
|
||||
|
||||
internal fun JavaAnnotation.toFirAnnotationCall(session: FirSession): FirAnnotationCall {
|
||||
return FirAnnotationCallImpl(
|
||||
session, psi = null, useSiteTarget = null,
|
||||
annotationTypeRef = FirResolvedTypeRefImpl(
|
||||
session = session,
|
||||
psi = null,
|
||||
type = ConeClassTypeImpl(FirClassSymbol(classId!!).toLookupTag(), emptyArray(), isNullable = false),
|
||||
isMarkedNullable = true,
|
||||
annotations = emptyList()
|
||||
)
|
||||
).apply {
|
||||
for (argument in this@toFirAnnotationCall.arguments) {
|
||||
arguments += argument.toFirExpression(session)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun FirAbstractAnnotatedElement.addAnnotationsFrom(javaAnnotationOwner: JavaAnnotationOwner) {
|
||||
for (annotation in javaAnnotationOwner.annotations) {
|
||||
annotations += annotation.toFirAnnotationCall(session)
|
||||
}
|
||||
}
|
||||
|
||||
private fun JavaType.toConeProjection(session: FirSession): ConeKotlinTypeProjection {
|
||||
if (this is JavaClassifierType) {
|
||||
return toConeKotlinTypeWithNullability(session, isNullable = false)
|
||||
}
|
||||
return ConeClassErrorType("Unexpected type argument: $this")
|
||||
}
|
||||
|
||||
private fun JavaAnnotationArgument.toFirExpression(session: FirSession): FirExpression {
|
||||
// TODO: this.name
|
||||
return when (this) {
|
||||
is JavaLiteralAnnotationArgument -> {
|
||||
when (val value = value) {
|
||||
is ByteArray -> value.toList().createArrayOfCall(session, IrConstKind.Byte)
|
||||
is ShortArray -> value.toList().createArrayOfCall(session, IrConstKind.Short)
|
||||
is IntArray -> value.toList().createArrayOfCall(session, IrConstKind.Int)
|
||||
is LongArray -> value.toList().createArrayOfCall(session, IrConstKind.Long)
|
||||
is CharArray -> value.toList().createArrayOfCall(session, IrConstKind.Char)
|
||||
is FloatArray -> value.toList().createArrayOfCall(session, IrConstKind.Float)
|
||||
is DoubleArray -> value.toList().createArrayOfCall(session, IrConstKind.Double)
|
||||
is BooleanArray -> value.toList().createArrayOfCall(session, IrConstKind.Boolean)
|
||||
else -> value.createConstant(session)
|
||||
}
|
||||
}
|
||||
is JavaArrayAnnotationArgument -> FirArrayOfCallImpl(session, null).apply {
|
||||
for (element in getElements()) {
|
||||
arguments += element.toFirExpression(session)
|
||||
}
|
||||
}
|
||||
is JavaEnumValueAnnotationArgument -> {
|
||||
FirFunctionCallImpl(session, null).apply {
|
||||
val classId = this@toFirExpression.enumClassId
|
||||
val entryName = this@toFirExpression.entryName
|
||||
val calleeReference = if (classId != null && entryName != null) {
|
||||
val callableSymbol = session.service<FirSymbolProvider>().getCallableSymbols(
|
||||
CallableId(classId.packageFqName, classId.relativeClassName, entryName)
|
||||
).firstOrNull()
|
||||
callableSymbol?.let {
|
||||
FirResolvedCallableReferenceImpl(session, null, entryName, it)
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
this.calleeReference = calleeReference
|
||||
?: FirErrorNamedReference(session, null, "Strange Java enum value: ${this@toFirExpression}")
|
||||
}
|
||||
}
|
||||
is JavaClassObjectAnnotationArgument -> FirGetClassCallImpl(session, null).apply {
|
||||
val referencedType = getReferencedType()
|
||||
arguments += FirClassReferenceExpressionImpl(session, null, referencedType.toFirResolvedTypeRef(session))
|
||||
}
|
||||
is JavaAnnotationAsAnnotationArgument -> getAnnotation().toFirAnnotationCall(session)
|
||||
else -> FirErrorExpressionImpl(session, null, "Unknown JavaAnnotationArgument: ${this::class.java}")
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: use kind here
|
||||
private fun <T> List<T>.createArrayOfCall(session: FirSession, @Suppress("UNUSED_PARAMETER") kind: IrConstKind<T>): FirArrayOfCall {
|
||||
return FirArrayOfCallImpl(session, null).apply {
|
||||
for (element in this@createArrayOfCall) {
|
||||
arguments += element.createConstant(session)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun Any?.createConstant(session: FirSession): FirExpression {
|
||||
return when (this) {
|
||||
is Byte -> FirConstExpressionImpl(session, null, IrConstKind.Byte, this)
|
||||
is Short -> FirConstExpressionImpl(session, null, IrConstKind.Short, this)
|
||||
is Int -> FirConstExpressionImpl(session, null, IrConstKind.Int, this)
|
||||
is Long -> FirConstExpressionImpl(session, null, IrConstKind.Long, this)
|
||||
is Char -> FirConstExpressionImpl(session, null, IrConstKind.Char, this)
|
||||
is Float -> FirConstExpressionImpl(session, null, IrConstKind.Float, this)
|
||||
is Double -> FirConstExpressionImpl(session, null, IrConstKind.Double, this)
|
||||
is Boolean -> FirConstExpressionImpl(session, null, IrConstKind.Boolean, this)
|
||||
is String -> FirConstExpressionImpl(session, null, IrConstKind.String, this)
|
||||
null -> FirConstExpressionImpl(session, null, IrConstKind.Null, null)
|
||||
|
||||
else -> FirErrorExpressionImpl(session, null, "Unknown value in JavaLiteralAnnotationArgument: $this")
|
||||
}
|
||||
}
|
||||
|
||||
private fun JavaType.toFirResolvedTypeRef(session: FirSession): FirResolvedTypeRef {
|
||||
if (this is JavaClassifierType) return toFirResolvedTypeRef(session)
|
||||
return FirResolvedTypeRefImpl(
|
||||
session, psi = null, type = ConeClassErrorType("Unexpected JavaType: $this"),
|
||||
isMarkedNullable = false, annotations = emptyList()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -5,26 +5,72 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.java.declarations
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.Visibility
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.impl.FirClassImpl
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||
import org.jetbrains.kotlin.fir.declarations.impl.FirAbstractMemberDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.impl.FirModifiableClass
|
||||
import org.jetbrains.kotlin.fir.java.scopes.JavaClassEnhancementScope
|
||||
import org.jetbrains.kotlin.fir.java.scopes.JavaClassUseSiteScope
|
||||
import org.jetbrains.kotlin.fir.resolve.lookupSuperTypes
|
||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.FirClassDeclaredMemberScope
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.FirCompositeScope
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||
import org.jetbrains.kotlin.fir.types.ConeClassErrorType
|
||||
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
class FirJavaClass(
|
||||
session: FirSession,
|
||||
symbol: FirClassSymbol,
|
||||
override val symbol: FirClassSymbol,
|
||||
name: Name,
|
||||
visibility: Visibility,
|
||||
modality: Modality?,
|
||||
classKind: ClassKind,
|
||||
override val classKind: ClassKind,
|
||||
isTopLevel: Boolean,
|
||||
isStatic: Boolean
|
||||
) : FirClassImpl(
|
||||
session, psi = null, symbol = symbol, name = name,
|
||||
) : FirAbstractMemberDeclaration(
|
||||
session, psi = null, name = name,
|
||||
visibility = visibility, modality = modality,
|
||||
isExpect = false, isActual = false, classKind = classKind, isInner = !isStatic,
|
||||
isCompanion = false, isData = false, isInline = false
|
||||
)
|
||||
isExpect = false, isActual = false
|
||||
), FirRegularClass, FirModifiableClass {
|
||||
init {
|
||||
symbol.bind(this)
|
||||
status.isInner = !isTopLevel && !isStatic
|
||||
status.isCompanion = false
|
||||
status.isData = false
|
||||
status.isInline = false
|
||||
}
|
||||
|
||||
override val superTypeRefs = mutableListOf<FirTypeRef>()
|
||||
|
||||
val useSiteScope: JavaClassUseSiteScope by lazy { buildUseSiteScope() }
|
||||
|
||||
override val declarations = mutableListOf<FirDeclaration>()
|
||||
|
||||
private fun FirRegularClass.buildUseSiteScope(useSiteSession: FirSession = session): JavaClassUseSiteScope {
|
||||
val superTypeEnhancementScope = FirCompositeScope(mutableListOf())
|
||||
val declaredScope = FirClassDeclaredMemberScope(this, useSiteSession)
|
||||
lookupSuperTypes(this, lookupInterfaces = true, deep = false, useSiteSession = useSiteSession)
|
||||
.mapNotNullTo(superTypeEnhancementScope.scopes) { useSiteSuperType ->
|
||||
if (useSiteSuperType is ConeClassErrorType) return@mapNotNullTo null
|
||||
val symbol = useSiteSuperType.lookupTag.toSymbol(useSiteSession)
|
||||
if (symbol is FirClassSymbol) {
|
||||
JavaClassEnhancementScope(useSiteSession, symbol.fir.buildUseSiteScope(useSiteSession))
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
return JavaClassUseSiteScope(this, useSiteSession, superTypeEnhancementScope, declaredScope)
|
||||
}
|
||||
|
||||
override fun replaceSupertypes(newSupertypes: List<FirTypeRef>): FirRegularClass {
|
||||
superTypeRefs.clear()
|
||||
superTypeRefs.addAll(newSupertypes)
|
||||
return this
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,7 @@ class FirJavaMethod(
|
||||
session, null, symbol, name,
|
||||
visibility, modality,
|
||||
false, isActual = false,
|
||||
isOverride = false, // TODO: really it's unknown whether Java methods are overrides or not
|
||||
isOverride = false,
|
||||
isOperator = true, // All Java methods with name that allows to use it in operator form are considered operators
|
||||
isInfix = false, isInline = false, isTailRec = false, isExternal = false, isSuspend = false,
|
||||
receiverTypeRef = null, returnTypeRef = returnTypeRef
|
||||
|
||||
+293
@@ -0,0 +1,293 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.fir.java.enhancement
|
||||
|
||||
import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
|
||||
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
|
||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
|
||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotationContainer
|
||||
import org.jetbrains.kotlin.fir.expressions.resolvedFqName
|
||||
import org.jetbrains.kotlin.fir.java.toConeKotlinTypeWithNullability
|
||||
import org.jetbrains.kotlin.fir.java.toFirJavaTypeRef
|
||||
import org.jetbrains.kotlin.fir.java.toNotNullConeKotlinType
|
||||
import org.jetbrains.kotlin.fir.java.types.FirJavaTypeRef
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.load.java.AnnotationTypeQualifierResolver
|
||||
import org.jetbrains.kotlin.load.java.MUTABLE_ANNOTATIONS
|
||||
import org.jetbrains.kotlin.load.java.READ_ONLY_ANNOTATIONS
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaWildcardType
|
||||
import org.jetbrains.kotlin.load.java.typeEnhancement.*
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.FqNameUnsafe
|
||||
import org.jetbrains.kotlin.utils.Jsr305State
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
internal class EnhancementSignatureParts(
|
||||
private val typeQualifierResolver: FirAnnotationTypeQualifierResolver,
|
||||
private val typeContainer: FirAnnotationContainer?,
|
||||
private val current: FirJavaTypeRef,
|
||||
private val fromOverridden: Collection<FirTypeRef>,
|
||||
private val isCovariant: Boolean,
|
||||
private val context: FirJavaEnhancementContext,
|
||||
private val containerApplicabilityType: AnnotationTypeQualifierResolver.QualifierApplicabilityType
|
||||
) {
|
||||
private val isForVarargParameter get() = typeContainer.safeAs<FirValueParameter>()?.isVararg == true
|
||||
|
||||
private fun ConeKotlinType.toFqNameUnsafe(): FqNameUnsafe? =
|
||||
((this as? ConeLookupTagBasedType)?.lookupTag as? ConeClassLikeLookupTag)?.classId?.asSingleFqName()?.toUnsafe()
|
||||
|
||||
internal fun enhance(
|
||||
jsr305State: Jsr305State,
|
||||
predefined: TypeEnhancementInfo? = null
|
||||
): PartEnhancementResult {
|
||||
val qualifiers = computeIndexedQualifiersForOverride(jsr305State)
|
||||
|
||||
val qualifiersWithPredefined: ((Int) -> JavaTypeQualifiers)? = predefined?.let {
|
||||
{ index ->
|
||||
predefined.map[index] ?: qualifiers(index)
|
||||
}
|
||||
}
|
||||
|
||||
val containsFunctionN = current.toNotNullConeKotlinType().contains {
|
||||
val classId = it.lookupTag.classId
|
||||
classId.shortClassName == JavaToKotlinClassMap.FUNCTION_N_FQ_NAME.shortName() &&
|
||||
classId.asSingleFqName() == JavaToKotlinClassMap.FUNCTION_N_FQ_NAME
|
||||
}
|
||||
|
||||
val enhancedCurrent = current.enhance(qualifiersWithPredefined ?: qualifiers)
|
||||
return PartEnhancementResult(
|
||||
enhancedCurrent, wereChanges = true, containsFunctionN = containsFunctionN
|
||||
)
|
||||
}
|
||||
|
||||
private fun ConeKotlinType.contains(isSpecialType: (ConeClassLikeType) -> Boolean): Boolean {
|
||||
return when (this) {
|
||||
is ConeClassLikeType -> isSpecialType(this)
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun FirTypeRef.toIndexed(
|
||||
typeQualifierResolver: FirAnnotationTypeQualifierResolver,
|
||||
jsr305State: Jsr305State,
|
||||
context: FirJavaEnhancementContext
|
||||
): List<TypeAndDefaultQualifiers> {
|
||||
val list = ArrayList<TypeAndDefaultQualifiers>(1)
|
||||
|
||||
fun add(type: FirTypeRef) {
|
||||
val c = context.copyWithNewDefaultTypeQualifiers(typeQualifierResolver, jsr305State, type.annotations)
|
||||
|
||||
list.add(
|
||||
TypeAndDefaultQualifiers(
|
||||
type,
|
||||
c.defaultTypeQualifiers
|
||||
?.get(AnnotationTypeQualifierResolver.QualifierApplicabilityType.TYPE_USE)
|
||||
)
|
||||
)
|
||||
|
||||
if (type is FirJavaTypeRef) {
|
||||
for (arg in type.type.typeArguments()) {
|
||||
if (arg is JavaWildcardType) {
|
||||
// TODO: wildcards
|
||||
} else {
|
||||
add(arg.toFirJavaTypeRef(context.session))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (arg in type.typeArguments()) {
|
||||
if (arg is FirStarProjection) {
|
||||
// TODO: wildcards
|
||||
} else if (arg is FirTypeProjectionWithVariance) {
|
||||
add(arg.typeRef)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
add(this)
|
||||
return list
|
||||
}
|
||||
|
||||
private fun extractQualifiers(lower: ConeKotlinType, upper: ConeKotlinType): JavaTypeQualifiers {
|
||||
val mapping = JavaToKotlinClassMap
|
||||
return JavaTypeQualifiers(
|
||||
when {
|
||||
lower.isMarkedNullable -> NullabilityQualifier.NULLABLE
|
||||
!upper.isMarkedNullable -> NullabilityQualifier.NOT_NULL
|
||||
else -> null
|
||||
},
|
||||
when {
|
||||
mapping.isReadOnly(lower.toFqNameUnsafe()) -> MutabilityQualifier.READ_ONLY
|
||||
mapping.isMutable(upper.toFqNameUnsafe()) -> MutabilityQualifier.MUTABLE
|
||||
else -> null
|
||||
},
|
||||
isNotNullTypeParameter = false //TODO: unwrap() is NotNullTypeParameter
|
||||
)
|
||||
}
|
||||
|
||||
private fun FirTypeRef.extractQualifiers(): JavaTypeQualifiers {
|
||||
val (lower, upper) = when (this) {
|
||||
is FirResolvedTypeRef -> {
|
||||
val type = this.type
|
||||
if (type is ConeFlexibleType) {
|
||||
Pair(type.lowerBound, type.upperBound)
|
||||
} else {
|
||||
Pair(type, type)
|
||||
}
|
||||
}
|
||||
is FirJavaTypeRef -> {
|
||||
Pair(
|
||||
// TODO: optimize
|
||||
type.toConeKotlinTypeWithNullability(session, isNullable = false),
|
||||
type.toConeKotlinTypeWithNullability(session, isNullable = true)
|
||||
)
|
||||
}
|
||||
else -> return JavaTypeQualifiers.NONE
|
||||
}
|
||||
|
||||
return extractQualifiers(lower, upper)
|
||||
}
|
||||
|
||||
private fun composeAnnotations(first: List<FirAnnotationCall>, second: List<FirAnnotationCall>): List<FirAnnotationCall> {
|
||||
return when {
|
||||
first.isEmpty() -> second
|
||||
second.isEmpty() -> first
|
||||
else -> first + second
|
||||
}
|
||||
}
|
||||
|
||||
private fun FirTypeRef.extractQualifiersFromAnnotations(
|
||||
isHeadTypeConstructor: Boolean,
|
||||
defaultQualifiersForType: JavaTypeQualifiers?,
|
||||
jsr305State: Jsr305State
|
||||
): JavaTypeQualifiers {
|
||||
val composedAnnotation =
|
||||
if (isHeadTypeConstructor && typeContainer != null)
|
||||
composeAnnotations(typeContainer.annotations, annotations)
|
||||
else
|
||||
annotations
|
||||
|
||||
fun <T : Any> List<FqName>.ifPresent(qualifier: T) =
|
||||
if (any { fqName ->
|
||||
composedAnnotation.any { it.resolvedFqName == fqName }
|
||||
}
|
||||
) qualifier else null
|
||||
|
||||
fun <T : Any> uniqueNotNull(x: T?, y: T?) = if (x == null || y == null || x == y) x ?: y else null
|
||||
|
||||
val defaultTypeQualifier =
|
||||
if (isHeadTypeConstructor)
|
||||
context.defaultTypeQualifiers?.get(containerApplicabilityType)
|
||||
else
|
||||
defaultQualifiersForType
|
||||
|
||||
val nullabilityInfo = composedAnnotation.extractNullability(typeQualifierResolver, jsr305State)
|
||||
?: defaultTypeQualifier?.nullability?.let { nullability ->
|
||||
NullabilityQualifierWithMigrationStatus(
|
||||
nullability,
|
||||
defaultTypeQualifier.isNullabilityQualifierForWarning
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("SimplifyBooleanWithConstants")
|
||||
return JavaTypeQualifiers(
|
||||
nullabilityInfo?.qualifier,
|
||||
uniqueNotNull(
|
||||
READ_ONLY_ANNOTATIONS.ifPresent(
|
||||
MutabilityQualifier.READ_ONLY
|
||||
),
|
||||
MUTABLE_ANNOTATIONS.ifPresent(
|
||||
MutabilityQualifier.MUTABLE
|
||||
)
|
||||
),
|
||||
isNotNullTypeParameter = nullabilityInfo?.qualifier == NullabilityQualifier.NOT_NULL && true, /* TODO: isTypeParameter()*/
|
||||
isNullabilityQualifierForWarning = nullabilityInfo?.isForWarningOnly == true
|
||||
)
|
||||
}
|
||||
|
||||
private fun FirTypeRef.computeQualifiersForOverride(
|
||||
fromSupertypes: Collection<FirTypeRef>,
|
||||
defaultQualifiersForType: JavaTypeQualifiers?,
|
||||
isHeadTypeConstructor: Boolean,
|
||||
jsr305State: Jsr305State
|
||||
): JavaTypeQualifiers {
|
||||
val superQualifiers = fromSupertypes.map { it.extractQualifiers() }
|
||||
val mutabilityFromSupertypes = superQualifiers.mapNotNull { it.mutability }.toSet()
|
||||
val nullabilityFromSupertypes = superQualifiers.mapNotNull { it.nullability }.toSet()
|
||||
val nullabilityFromSupertypesWithWarning = fromOverridden
|
||||
.mapNotNull { it.extractQualifiers().nullability }
|
||||
.toSet()
|
||||
|
||||
val own = extractQualifiersFromAnnotations(isHeadTypeConstructor, defaultQualifiersForType, jsr305State)
|
||||
val ownNullability = own.takeIf { !it.isNullabilityQualifierForWarning }?.nullability
|
||||
val ownNullabilityForWarning = own.nullability
|
||||
|
||||
val isCovariantPosition = isCovariant && isHeadTypeConstructor
|
||||
val nullability =
|
||||
nullabilityFromSupertypes.select(ownNullability, isCovariantPosition)
|
||||
// Vararg value parameters effectively have non-nullable type in Kotlin
|
||||
// and having nullable types in Java may lead to impossibility of overriding them in Kotlin
|
||||
?.takeUnless { isForVarargParameter && isHeadTypeConstructor && it == NullabilityQualifier.NULLABLE }
|
||||
|
||||
val mutability =
|
||||
mutabilityFromSupertypes
|
||||
.select(MutabilityQualifier.MUTABLE, MutabilityQualifier.READ_ONLY, own.mutability, isCovariantPosition)
|
||||
|
||||
val canChange = ownNullabilityForWarning != ownNullability || nullabilityFromSupertypesWithWarning != nullabilityFromSupertypes
|
||||
val isAnyNonNullTypeParameter = own.isNotNullTypeParameter || superQualifiers.any { it.isNotNullTypeParameter }
|
||||
if (nullability == null && canChange) {
|
||||
val nullabilityWithWarning =
|
||||
nullabilityFromSupertypesWithWarning.select(ownNullabilityForWarning, isCovariantPosition)
|
||||
|
||||
return createJavaTypeQualifiers(
|
||||
nullabilityWithWarning, mutability,
|
||||
forWarning = true, isAnyNonNullTypeParameter = isAnyNonNullTypeParameter
|
||||
)
|
||||
}
|
||||
|
||||
return createJavaTypeQualifiers(
|
||||
nullability, mutability,
|
||||
forWarning = nullability == null,
|
||||
isAnyNonNullTypeParameter = isAnyNonNullTypeParameter
|
||||
)
|
||||
}
|
||||
|
||||
private fun computeIndexedQualifiersForOverride(jsr305State: Jsr305State): (Int) -> JavaTypeQualifiers {
|
||||
val indexedFromSupertypes = fromOverridden.map { it.toIndexed(typeQualifierResolver, jsr305State, context) }
|
||||
val indexedThisType = current.toIndexed(typeQualifierResolver, jsr305State, context)
|
||||
|
||||
// The covariant case may be hard, e.g. in the superclass the return may be Super<T>, but in the subclass it may be Derived, which
|
||||
// is declared to extend Super<T>, and propagating data here is highly non-trivial, so we only look at the head type constructor
|
||||
// (outermost type), unless the type in the subclass is interchangeable with the all the types in superclasses:
|
||||
// e.g. we have (Mutable)List<String!>! in the subclass and { List<String!>, (Mutable)List<String>! } from superclasses
|
||||
// Note that `this` is flexible here, so it's equal to it's bounds
|
||||
val onlyHeadTypeConstructor = isCovariant && fromOverridden.any { true /*equalTypes(it, this)*/ }
|
||||
|
||||
val treeSize = if (onlyHeadTypeConstructor) 1 else indexedThisType.size
|
||||
val computedResult = Array(treeSize) { index ->
|
||||
val isHeadTypeConstructor = index == 0
|
||||
assert(isHeadTypeConstructor || !onlyHeadTypeConstructor) { "Only head type constructors should be computed" }
|
||||
|
||||
val (qualifiers, defaultQualifiers) = indexedThisType[index]
|
||||
val verticalSlice = indexedFromSupertypes.mapNotNull { it.getOrNull(index)?.type }
|
||||
|
||||
// Only the head type constructor is safely co-variant
|
||||
qualifiers.computeQualifiersForOverride(verticalSlice, defaultQualifiers, isHeadTypeConstructor, jsr305State)
|
||||
}
|
||||
|
||||
return { index -> computedResult.getOrElse(index) { JavaTypeQualifiers.NONE } }
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
internal open class PartEnhancementResult(
|
||||
val type: FirResolvedTypeRef,
|
||||
val wereChanges: Boolean,
|
||||
val containsFunctionN: Boolean
|
||||
)
|
||||
}
|
||||
|
||||
+157
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.fir.java.enhancement
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
||||
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
|
||||
import org.jetbrains.kotlin.load.java.*
|
||||
import org.jetbrains.kotlin.load.java.lazy.NullabilityQualifierWithApplicability
|
||||
import org.jetbrains.kotlin.utils.Jsr305State
|
||||
import org.jetbrains.kotlin.utils.ReportLevel
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
|
||||
|
||||
class FirAnnotationTypeQualifierResolver(private val jsr305State: Jsr305State) {
|
||||
|
||||
class TypeQualifierWithApplicability(
|
||||
private val typeQualifier: FirAnnotationCall,
|
||||
private val applicability: Int
|
||||
) {
|
||||
operator fun component1() = typeQualifier
|
||||
operator fun component2() = AnnotationTypeQualifierResolver.QualifierApplicabilityType.values().filter(this::isApplicableTo)
|
||||
|
||||
private fun isApplicableTo(elementType: AnnotationTypeQualifierResolver.QualifierApplicabilityType) =
|
||||
isApplicableConsideringMask(AnnotationTypeQualifierResolver.QualifierApplicabilityType.TYPE_USE) || isApplicableConsideringMask(
|
||||
elementType
|
||||
)
|
||||
|
||||
private fun isApplicableConsideringMask(elementType: AnnotationTypeQualifierResolver.QualifierApplicabilityType) =
|
||||
(applicability and (1 shl elementType.ordinal)) != 0
|
||||
}
|
||||
|
||||
// TODO: memoize this function
|
||||
private fun computeTypeQualifierNickname(klass: FirRegularClass): FirAnnotationCall? {
|
||||
if (klass.annotations.none { it.resolvedFqName == TYPE_QUALIFIER_NICKNAME_FQNAME }) return null
|
||||
|
||||
return klass.annotations.firstNotNullResult(this::resolveTypeQualifierAnnotation)
|
||||
}
|
||||
|
||||
private fun resolveTypeQualifierNickname(klass: FirRegularClass): FirAnnotationCall? {
|
||||
if (klass.classKind != ClassKind.ANNOTATION_CLASS) return null
|
||||
|
||||
return computeTypeQualifierNickname(klass)
|
||||
}
|
||||
|
||||
private val FirAnnotationCall.resolvedClass: FirRegularClass?
|
||||
get() {
|
||||
val lookupTag = ((annotationTypeRef as? FirResolvedTypeRef)?.type as? ConeClassLikeType)?.lookupTag
|
||||
return (lookupTag?.toSymbol(session) as? FirClassSymbol)?.fir
|
||||
}
|
||||
|
||||
fun resolveTypeQualifierAnnotation(annotationCall: FirAnnotationCall): FirAnnotationCall? {
|
||||
if (jsr305State.disabled) {
|
||||
return null
|
||||
}
|
||||
|
||||
val annotationClass = annotationCall.resolvedClass ?: return null
|
||||
if (annotationClass.isAnnotatedWithTypeQualifier) return annotationCall
|
||||
|
||||
return resolveTypeQualifierNickname(annotationClass)
|
||||
}
|
||||
|
||||
fun resolveQualifierBuiltInDefaultAnnotation(annotationCall: FirAnnotationCall): NullabilityQualifierWithApplicability? {
|
||||
if (jsr305State.disabled) {
|
||||
return null
|
||||
}
|
||||
|
||||
return BUILT_IN_TYPE_QUALIFIER_DEFAULT_ANNOTATIONS[annotationCall.resolvedFqName]?.let { (qualifier, applicability) ->
|
||||
val state = resolveJsr305ReportLevel(annotationCall).takeIf { it != ReportLevel.IGNORE } ?: return null
|
||||
return NullabilityQualifierWithApplicability(qualifier.copy(isForWarningOnly = state.isWarning), applicability)
|
||||
}
|
||||
}
|
||||
|
||||
fun resolveTypeQualifierDefaultAnnotation(annotationCall: FirAnnotationCall): TypeQualifierWithApplicability? {
|
||||
if (jsr305State.disabled) {
|
||||
return null
|
||||
}
|
||||
|
||||
val typeQualifierDefaultAnnotatedClass =
|
||||
annotationCall.resolvedClass?.takeIf { klass ->
|
||||
klass.annotations.any { it.resolvedFqName == TYPE_QUALIFIER_DEFAULT_FQNAME }
|
||||
} ?: return null
|
||||
|
||||
val elementTypesMask =
|
||||
annotationCall.resolvedClass!!
|
||||
.annotations.find { it.resolvedFqName == TYPE_QUALIFIER_DEFAULT_FQNAME }!!
|
||||
.arguments
|
||||
.flatMap { argument ->
|
||||
// TODO: replace after implementation of KT-24081
|
||||
if (true /*parameter == JvmAnnotationNames.DEFAULT_ANNOTATION_MEMBER_NAME*/)
|
||||
argument.mapConstantToQualifierApplicabilityTypes()
|
||||
else
|
||||
emptyList()
|
||||
}
|
||||
.fold(0) { acc: Int, applicabilityType -> acc or (1 shl applicabilityType.ordinal) }
|
||||
|
||||
val typeQualifier = typeQualifierDefaultAnnotatedClass.annotations.firstOrNull { resolveTypeQualifierAnnotation(it) != null }
|
||||
?: return null
|
||||
|
||||
return TypeQualifierWithApplicability(
|
||||
typeQualifier,
|
||||
elementTypesMask
|
||||
)
|
||||
}
|
||||
|
||||
fun resolveJsr305ReportLevel(annotationCall: FirAnnotationCall): ReportLevel {
|
||||
resolveJsr305CustomLevel(annotationCall)?.let { return it }
|
||||
return jsr305State.global
|
||||
}
|
||||
|
||||
fun resolveJsr305CustomLevel(annotationCall: FirAnnotationCall): ReportLevel? {
|
||||
jsr305State.user[annotationCall.resolvedFqName?.asString()]?.let { return it }
|
||||
return annotationCall.resolvedClass?.migrationAnnotationStatus()
|
||||
}
|
||||
|
||||
private fun FirRegularClass.migrationAnnotationStatus(): ReportLevel? {
|
||||
val enumEntryName = annotations.find {
|
||||
it.resolvedFqName == MIGRATION_ANNOTATION_FQNAME
|
||||
}?.arguments?.firstOrNull()?.toResolvedCallableSymbol()?.callableId?.callableName ?: return null
|
||||
|
||||
jsr305State.migration?.let { return it }
|
||||
|
||||
return when (enumEntryName.asString()) {
|
||||
"STRICT" -> ReportLevel.STRICT
|
||||
"WARN" -> ReportLevel.WARN
|
||||
"IGNORE" -> ReportLevel.IGNORE
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun FirExpression.mapConstantToQualifierApplicabilityTypes(): List<AnnotationTypeQualifierResolver.QualifierApplicabilityType> =
|
||||
when (this) {
|
||||
is FirArrayOfCall -> arguments.flatMap { it.mapConstantToQualifierApplicabilityTypes() }
|
||||
else -> listOfNotNull(
|
||||
when (toResolvedCallableSymbol()?.callableId?.callableName?.asString()) {
|
||||
"METHOD" -> AnnotationTypeQualifierResolver.QualifierApplicabilityType.METHOD_RETURN_TYPE
|
||||
"FIELD" -> AnnotationTypeQualifierResolver.QualifierApplicabilityType.FIELD
|
||||
"PARAMETER" -> AnnotationTypeQualifierResolver.QualifierApplicabilityType.VALUE_PARAMETER
|
||||
"TYPE_USE" -> AnnotationTypeQualifierResolver.QualifierApplicabilityType.TYPE_USE
|
||||
else -> null
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
val disabled: Boolean = jsr305State.disabled
|
||||
|
||||
}
|
||||
|
||||
private val FirRegularClass.isAnnotatedWithTypeQualifier: Boolean
|
||||
get() = this.symbol.classId.asSingleFqName() in BUILT_IN_TYPE_QUALIFIER_FQ_NAMES ||
|
||||
annotations.any { it.resolvedFqName == TYPE_QUALIFIER_FQNAME }
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.fir.java.enhancement
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
|
||||
import org.jetbrains.kotlin.load.java.AnnotationTypeQualifierResolver
|
||||
import org.jetbrains.kotlin.load.java.lazy.JavaTypeQualifiersByElementType
|
||||
import org.jetbrains.kotlin.load.java.lazy.NullabilityQualifierWithApplicability
|
||||
import org.jetbrains.kotlin.load.java.lazy.QualifierByApplicabilityType
|
||||
import org.jetbrains.kotlin.utils.Jsr305State
|
||||
|
||||
class FirJavaEnhancementContext private constructor(
|
||||
val session: FirSession,
|
||||
delegateForDefaultTypeQualifiers: Lazy<JavaTypeQualifiersByElementType?>
|
||||
) {
|
||||
constructor(session: FirSession, typeQualifiersComputation: () -> JavaTypeQualifiersByElementType?) :
|
||||
this(session, lazy(LazyThreadSafetyMode.NONE, typeQualifiersComputation))
|
||||
|
||||
val defaultTypeQualifiers: JavaTypeQualifiersByElementType? by delegateForDefaultTypeQualifiers
|
||||
|
||||
val moduleInfo get() = session.moduleInfo
|
||||
}
|
||||
|
||||
fun extractDefaultNullabilityQualifier(
|
||||
typeQualifierResolver: FirAnnotationTypeQualifierResolver,
|
||||
jsr305State: Jsr305State,
|
||||
annotationCall: FirAnnotationCall
|
||||
): NullabilityQualifierWithApplicability? {
|
||||
typeQualifierResolver.resolveQualifierBuiltInDefaultAnnotation(annotationCall)?.let { return it }
|
||||
|
||||
val (typeQualifier, applicability) =
|
||||
typeQualifierResolver.resolveTypeQualifierDefaultAnnotation(annotationCall)
|
||||
?: return null
|
||||
|
||||
val jsr305ReportLevel = with(typeQualifierResolver) {
|
||||
resolveJsr305CustomLevel(annotationCall) ?: resolveJsr305ReportLevel(typeQualifier)
|
||||
}
|
||||
|
||||
if (jsr305ReportLevel.isIgnore) {
|
||||
return null
|
||||
}
|
||||
|
||||
val nullabilityQualifier = typeQualifier.extractNullability(
|
||||
typeQualifierResolver, jsr305State
|
||||
)?.copy(isForWarningOnly = jsr305ReportLevel.isWarning) ?: return null
|
||||
|
||||
return NullabilityQualifierWithApplicability(nullabilityQualifier, applicability)
|
||||
}
|
||||
|
||||
fun FirJavaEnhancementContext.computeNewDefaultTypeQualifiers(
|
||||
typeQualifierResolver: FirAnnotationTypeQualifierResolver,
|
||||
jsr305State: Jsr305State,
|
||||
additionalAnnotations: List<FirAnnotationCall>
|
||||
): JavaTypeQualifiersByElementType? {
|
||||
if (typeQualifierResolver.disabled) return defaultTypeQualifiers
|
||||
|
||||
val nullabilityQualifiersWithApplicability =
|
||||
additionalAnnotations.mapNotNull { annotationCall ->
|
||||
extractDefaultNullabilityQualifier(
|
||||
typeQualifierResolver,
|
||||
jsr305State,
|
||||
annotationCall
|
||||
)
|
||||
}
|
||||
|
||||
if (nullabilityQualifiersWithApplicability.isEmpty()) return defaultTypeQualifiers
|
||||
|
||||
val nullabilityQualifiersByType =
|
||||
defaultTypeQualifiers?.nullabilityQualifiers?.let(::QualifierByApplicabilityType)
|
||||
?: QualifierByApplicabilityType(AnnotationTypeQualifierResolver.QualifierApplicabilityType::class.java)
|
||||
|
||||
var wasUpdate = false
|
||||
for ((nullability, applicableTo) in nullabilityQualifiersWithApplicability) {
|
||||
for (applicabilityType in applicableTo) {
|
||||
nullabilityQualifiersByType[applicabilityType] = nullability
|
||||
wasUpdate = true
|
||||
}
|
||||
}
|
||||
|
||||
return if (!wasUpdate) defaultTypeQualifiers else JavaTypeQualifiersByElementType(nullabilityQualifiersByType)
|
||||
}
|
||||
|
||||
fun FirJavaEnhancementContext.copyWithNewDefaultTypeQualifiers(
|
||||
typeQualifierResolver: FirAnnotationTypeQualifierResolver,
|
||||
jsr305State: Jsr305State,
|
||||
additionalAnnotations: List<FirAnnotationCall>
|
||||
): FirJavaEnhancementContext =
|
||||
when {
|
||||
additionalAnnotations.isEmpty() -> this
|
||||
else -> FirJavaEnhancementContext(session) {
|
||||
computeNewDefaultTypeQualifiers(typeQualifierResolver, jsr305State, additionalAnnotations)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.fir.java.enhancement
|
||||
|
||||
import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
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.java.createTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.fir.java.toConeKotlinTypeWithNullability
|
||||
import org.jetbrains.kotlin.fir.java.toNotNullConeKotlinType
|
||||
import org.jetbrains.kotlin.fir.java.types.FirJavaTypeRef
|
||||
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.constructType
|
||||
import org.jetbrains.kotlin.fir.resolve.toTypeProjection
|
||||
import org.jetbrains.kotlin.fir.service
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeClassifierSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.types.impl.FirResolvedTypeRefImpl
|
||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
|
||||
import org.jetbrains.kotlin.load.java.descriptors.AnnotationDefaultValue
|
||||
import org.jetbrains.kotlin.load.java.descriptors.NullDefaultValue
|
||||
import org.jetbrains.kotlin.load.java.descriptors.StringDefaultValue
|
||||
import org.jetbrains.kotlin.load.java.structure.*
|
||||
import org.jetbrains.kotlin.load.java.typeEnhancement.*
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
internal fun FirJavaTypeRef.enhance(
|
||||
qualifiers: (Int) -> JavaTypeQualifiers
|
||||
): FirResolvedTypeRef {
|
||||
return type.enhancePossiblyFlexible(session, annotations, qualifiers, 0)
|
||||
}
|
||||
|
||||
// The index in the lambda is the position of the type component:
|
||||
// Example: for `A<B, C<D, E>>`, indices go as follows: `0 - A<...>, 1 - B, 2 - C<D, E>, 3 - D, 4 - E`,
|
||||
// which corresponds to the left-to-right breadth-first walk of the tree representation of the type.
|
||||
// For flexible types, both bounds are indexed in the same way: `(A<B>..C<D>)` gives `0 - (A<B>..C<D>), 1 - B and D`.
|
||||
private fun JavaType.enhancePossiblyFlexible(
|
||||
session: FirSession,
|
||||
annotations: List<FirAnnotationCall>,
|
||||
qualifiers: (Int) -> JavaTypeQualifiers,
|
||||
index: Int
|
||||
): FirResolvedTypeRef {
|
||||
val type = this
|
||||
val arguments = typeArguments()
|
||||
return when (type) {
|
||||
is JavaClassifierType -> {
|
||||
val lowerResult = type.enhanceInflexibleType(
|
||||
session, annotations, arguments, TypeComponentPosition.FLEXIBLE_LOWER, qualifiers, index
|
||||
)
|
||||
val upperResult = type.enhanceInflexibleType(
|
||||
session, annotations, arguments, TypeComponentPosition.FLEXIBLE_UPPER, qualifiers, index
|
||||
)
|
||||
|
||||
FirResolvedTypeRefImpl(
|
||||
session, psi = null,
|
||||
type = ConeFlexibleType(lowerResult, upperResult),
|
||||
isMarkedNullable = false, annotations = annotations
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
val enhanced = type.toNotNullConeKotlinType(session)
|
||||
FirResolvedTypeRefImpl(session, psi = null, type = enhanced, isMarkedNullable = false, annotations = annotations)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun JavaType.subtreeSize(): Int {
|
||||
if (this !is JavaClassifierType) return 1
|
||||
return 1 + typeArguments.sumBy { it.subtreeSize() }
|
||||
}
|
||||
|
||||
private fun JavaClassifierType.enhanceInflexibleType(
|
||||
session: FirSession,
|
||||
annotations: List<FirAnnotationCall>,
|
||||
arguments: List<JavaType>,
|
||||
position: TypeComponentPosition,
|
||||
qualifiers: (Int) -> JavaTypeQualifiers,
|
||||
index: Int
|
||||
): ConeLookupTagBasedType {
|
||||
val originalSymbol = when (val classifier = classifier) {
|
||||
is JavaClass -> session.service<FirSymbolProvider>().getClassLikeSymbolByFqName(classifier.classId!!)!!
|
||||
is JavaTypeParameter -> createTypeParameterSymbol(session, classifier.name)
|
||||
else -> return toNotNullConeKotlinType(session)
|
||||
}
|
||||
|
||||
val effectiveQualifiers = qualifiers(index)
|
||||
val (enhancedSymbol, mutabilityChanged) = originalSymbol.enhanceMutability(effectiveQualifiers, position)
|
||||
|
||||
var globalArgIndex = index + 1
|
||||
var wereChanges = mutabilityChanged
|
||||
val enhancedArguments = arguments.mapIndexed { localArgIndex, arg ->
|
||||
if (arg is JavaWildcardType) {
|
||||
globalArgIndex++
|
||||
ConeStarProjection
|
||||
// TODO: (?) TypeUtils.makeStarProjection(enhancedClassifier.typeConstructor.parameters[localArgIndex])
|
||||
} else {
|
||||
val argEnhancedTypeRef = arg.enhancePossiblyFlexible(session, annotations, qualifiers, globalArgIndex)
|
||||
wereChanges = wereChanges || argEnhancedTypeRef !== arg
|
||||
globalArgIndex += arg.subtreeSize()
|
||||
argEnhancedTypeRef.type.type.toTypeProjection(Variance.INVARIANT)
|
||||
}
|
||||
}
|
||||
|
||||
val (enhancedNullability, _, nullabilityChanged) = getEnhancedNullability(effectiveQualifiers, position)
|
||||
wereChanges = wereChanges || nullabilityChanged
|
||||
|
||||
if (!wereChanges) return toConeKotlinTypeWithNullability(
|
||||
session, isNullable = position == TypeComponentPosition.FLEXIBLE_UPPER
|
||||
)
|
||||
|
||||
val enhancedType = enhancedSymbol.constructType(enhancedArguments.toTypedArray(), enhancedNullability)
|
||||
|
||||
// TODO: why all of these is needed
|
||||
// val enhancement = if (effectiveQualifiers.isNotNullTypeParameter) NotNullTypeParameter(enhancedType) else enhancedType
|
||||
// val nullabilityForWarning = nullabilityChanged && effectiveQualifiers.isNullabilityQualifierForWarning
|
||||
// val result = if (nullabilityForWarning) wrapEnhancement(enhancement) else enhancement
|
||||
|
||||
return enhancedType
|
||||
}
|
||||
|
||||
private fun getEnhancedNullability(
|
||||
qualifiers: JavaTypeQualifiers,
|
||||
position: TypeComponentPosition
|
||||
): EnhanceDetailsResult<Boolean> {
|
||||
if (!position.shouldEnhance()) return false.noChange()
|
||||
|
||||
return when (qualifiers.nullability) {
|
||||
NullabilityQualifier.NULLABLE -> true.enhancedNullability()
|
||||
NullabilityQualifier.NOT_NULL -> false.enhancedNullability()
|
||||
else -> false.noChange()
|
||||
}
|
||||
}
|
||||
|
||||
private data class EnhanceDetailsResult<out T>(
|
||||
val result: T,
|
||||
val mutabilityChanged: Boolean = false,
|
||||
val nullabilityChanged: Boolean = false
|
||||
)
|
||||
|
||||
private fun <T> T.noChange() = EnhanceDetailsResult(this)
|
||||
private fun <T> T.enhancedNullability() = EnhanceDetailsResult(this, nullabilityChanged = true)
|
||||
private fun <T> T.enhancedMutability() = EnhanceDetailsResult(this, mutabilityChanged = true)
|
||||
|
||||
private fun ConeClassifierSymbol.enhanceMutability(
|
||||
qualifiers: JavaTypeQualifiers,
|
||||
position: TypeComponentPosition
|
||||
): EnhanceDetailsResult<ConeClassifierSymbol> {
|
||||
if (!position.shouldEnhance()) return this.noChange()
|
||||
if (this !is FirClassSymbol) return this.noChange() // mutability is not applicable for type parameters
|
||||
val fqNameUnsafe = classId.asSingleFqName().toUnsafe()
|
||||
|
||||
when (qualifiers.mutability) {
|
||||
MutabilityQualifier.READ_ONLY -> {
|
||||
val readOnlyFqName = JavaToKotlinClassMap.mutableToReadOnly(fqNameUnsafe)
|
||||
if (position == TypeComponentPosition.FLEXIBLE_LOWER && readOnlyFqName != null) {
|
||||
return FirClassSymbol(ClassId(classId.packageFqName, readOnlyFqName, false)).apply {
|
||||
bind(fir)
|
||||
}.enhancedMutability()
|
||||
}
|
||||
}
|
||||
MutabilityQualifier.MUTABLE -> {
|
||||
val mutableFqName = JavaToKotlinClassMap.readOnlyToMutable(fqNameUnsafe)
|
||||
if (position == TypeComponentPosition.FLEXIBLE_UPPER && mutableFqName != null) {
|
||||
return FirClassSymbol(ClassId(classId.packageFqName, mutableFqName, false)).apply {
|
||||
bind(fir)
|
||||
}.enhancedMutability()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this.noChange()
|
||||
}
|
||||
|
||||
|
||||
internal data class TypeAndDefaultQualifiers(
|
||||
val type: FirTypeRef,
|
||||
val defaultQualifiers: JavaTypeQualifiers?
|
||||
)
|
||||
|
||||
internal fun FirTypeRef.typeArguments(): List<FirTypeProjection> =
|
||||
(this as? FirUserTypeRef)?.qualifier?.lastOrNull()?.typeArguments.orEmpty()
|
||||
|
||||
internal fun JavaType.typeArguments(): List<JavaType> = (this as? JavaClassifierType)?.typeArguments.orEmpty()
|
||||
|
||||
fun FirValueParameter.getDefaultValueFromAnnotation(): AnnotationDefaultValue? {
|
||||
annotations.find { it.resolvedFqName == JvmAnnotationNames.DEFAULT_VALUE_FQ_NAME }
|
||||
?.arguments?.firstOrNull()
|
||||
?.safeAs<FirConstExpression<*>>()?.value?.safeAs<String>()
|
||||
?.let { return StringDefaultValue(it) }
|
||||
|
||||
if (annotations.any { it.resolvedFqName == JvmAnnotationNames.DEFAULT_NULL_FQ_NAME }) {
|
||||
return NullDefaultValue
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.fir.java.enhancement
|
||||
|
||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
|
||||
import org.jetbrains.kotlin.fir.expressions.resolvedFqName
|
||||
import org.jetbrains.kotlin.fir.expressions.toResolvedCallableSymbol
|
||||
import org.jetbrains.kotlin.load.java.*
|
||||
import org.jetbrains.kotlin.load.java.typeEnhancement.NullabilityQualifier
|
||||
import org.jetbrains.kotlin.load.java.typeEnhancement.NullabilityQualifierWithMigrationStatus
|
||||
import org.jetbrains.kotlin.utils.Jsr305State
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
|
||||
|
||||
fun List<FirAnnotationCall>.extractNullability(
|
||||
annotationTypeQualifierResolver: FirAnnotationTypeQualifierResolver,
|
||||
jsr305State: Jsr305State
|
||||
): NullabilityQualifierWithMigrationStatus? =
|
||||
this.firstNotNullResult { annotationCall ->
|
||||
annotationCall.extractNullability(annotationTypeQualifierResolver, jsr305State)
|
||||
}
|
||||
|
||||
|
||||
fun FirAnnotationCall.extractNullability(
|
||||
annotationTypeQualifierResolver: FirAnnotationTypeQualifierResolver,
|
||||
jsr305State: Jsr305State
|
||||
): NullabilityQualifierWithMigrationStatus? {
|
||||
this.extractNullabilityFromKnownAnnotations(jsr305State)?.let { return it }
|
||||
|
||||
val typeQualifierAnnotation =
|
||||
annotationTypeQualifierResolver.resolveTypeQualifierAnnotation(this)
|
||||
?: return null
|
||||
|
||||
val jsr305ReportLevel = annotationTypeQualifierResolver.resolveJsr305ReportLevel(this)
|
||||
if (jsr305ReportLevel.isIgnore) return null
|
||||
|
||||
return typeQualifierAnnotation.extractNullabilityFromKnownAnnotations(jsr305State)?.copy(isForWarningOnly = jsr305ReportLevel.isWarning)
|
||||
}
|
||||
|
||||
private fun FirAnnotationCall.extractNullabilityFromKnownAnnotations(jsr305State: Jsr305State): NullabilityQualifierWithMigrationStatus? {
|
||||
val annotationFqName = resolvedFqName ?: return null
|
||||
|
||||
return when {
|
||||
annotationFqName in NULLABLE_ANNOTATIONS -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NULLABLE)
|
||||
annotationFqName in NOT_NULL_ANNOTATIONS -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL)
|
||||
annotationFqName == JAVAX_NONNULL_ANNOTATION -> extractNullabilityTypeFromArgument()
|
||||
|
||||
annotationFqName == COMPATQUAL_NULLABLE_ANNOTATION && jsr305State.enableCompatqualCheckerFrameworkAnnotations ->
|
||||
NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NULLABLE)
|
||||
|
||||
annotationFqName == COMPATQUAL_NONNULL_ANNOTATION && jsr305State.enableCompatqualCheckerFrameworkAnnotations ->
|
||||
NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL)
|
||||
|
||||
annotationFqName == ANDROIDX_RECENTLY_NON_NULL_ANNOTATION -> NullabilityQualifierWithMigrationStatus(
|
||||
NullabilityQualifier.NOT_NULL,
|
||||
isForWarningOnly = true
|
||||
)
|
||||
|
||||
annotationFqName == ANDROIDX_RECENTLY_NULLABLE_ANNOTATION -> NullabilityQualifierWithMigrationStatus(
|
||||
NullabilityQualifier.NULLABLE,
|
||||
isForWarningOnly = true
|
||||
)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun FirAnnotationCall.extractNullabilityTypeFromArgument(): NullabilityQualifierWithMigrationStatus? {
|
||||
val enumValue = this.arguments.firstOrNull()?.toResolvedCallableSymbol()?.callableId?.callableName
|
||||
// if no argument is specified, use default value: NOT_NULL
|
||||
?: return NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL)
|
||||
|
||||
return when (enumValue.asString()) {
|
||||
"ALWAYS" -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL)
|
||||
"MAYBE", "NEVER" -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NULLABLE)
|
||||
"UNKNOWN" -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.FORCE_FLEXIBILITY)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
+259
@@ -0,0 +1,259 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.fir.java.scopes
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.impl.FirMemberFunctionImpl
|
||||
import org.jetbrains.kotlin.fir.declarations.impl.FirValueParameterImpl
|
||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotationContainer
|
||||
import org.jetbrains.kotlin.fir.java.declarations.FirJavaMethod
|
||||
import org.jetbrains.kotlin.fir.java.declarations.FirJavaValueParameter
|
||||
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
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||
import org.jetbrains.kotlin.load.java.AnnotationTypeQualifierResolver
|
||||
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
|
||||
import org.jetbrains.kotlin.load.kotlin.SignatureBuildingComponents
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.utils.Jsr305State
|
||||
|
||||
class JavaClassEnhancementScope(
|
||||
session: FirSession,
|
||||
private val useSiteScope: JavaClassUseSiteScope
|
||||
) : FirScope {
|
||||
private val owner: FirRegularClass get() = useSiteScope.symbol.fir
|
||||
|
||||
private val jsr305State: Jsr305State = session.jsr305State ?: Jsr305State.DEFAULT
|
||||
|
||||
private val typeQualifierResolver = FirAnnotationTypeQualifierResolver(jsr305State)
|
||||
|
||||
private val context: FirJavaEnhancementContext =
|
||||
FirJavaEnhancementContext(session) { null }
|
||||
|
||||
private val enhancements = mutableMapOf<ConeCallableSymbol, ConeCallableSymbol>()
|
||||
|
||||
override fun processFunctionsByName(name: Name, processor: (ConeFunctionSymbol) -> ProcessorAction): ProcessorAction {
|
||||
useSiteScope.processFunctionsByName(name) process@{ original ->
|
||||
|
||||
val function = enhancements.getOrPut(original) { enhance(original, name) }
|
||||
processor(function as ConeFunctionSymbol)
|
||||
}
|
||||
|
||||
return super.processFunctionsByName(name, processor)
|
||||
}
|
||||
|
||||
private fun enhance(
|
||||
original: ConeFunctionSymbol,
|
||||
name: Name
|
||||
): FirFunctionSymbol {
|
||||
val firMethod = (original as FirBasedSymbol<*>).fir as? FirJavaMethod ?: error("Can't fake override for $original")
|
||||
|
||||
val memberContext = context.copyWithNewDefaultTypeQualifiers(
|
||||
typeQualifierResolver, jsr305State, firMethod.annotations
|
||||
)
|
||||
// TODO: When loading method as an override for a property, all annotations are stick to its getter
|
||||
// if (this is FirProperty && getter !is FirDefaultPropertyAccessor)
|
||||
// getter
|
||||
// else
|
||||
// this
|
||||
|
||||
val predefinedEnhancementInfo =
|
||||
SignatureBuildingComponents.signature(owner.symbol.classId, firMethod.computeJvmDescriptor()).let { signature ->
|
||||
PREDEFINED_FUNCTION_ENHANCEMENT_INFO_BY_SIGNATURE[signature]
|
||||
}
|
||||
|
||||
predefinedEnhancementInfo?.let {
|
||||
assert(it.parametersInfo.size == firMethod.valueParameters.size) {
|
||||
"Predefined enhancement info for $this has ${it.parametersInfo.size}, but ${firMethod.valueParameters.size} expected"
|
||||
}
|
||||
}
|
||||
|
||||
val newReceiverTypeRef = if (firMethod.receiverTypeRef != null) enhanceReceiverType(firMethod, memberContext) else null
|
||||
val newReturnTypeRef = enhanceReturnType(firMethod, memberContext, predefinedEnhancementInfo)
|
||||
|
||||
val newValueParameterTypeRefs = mutableListOf<FirResolvedTypeRef>()
|
||||
|
||||
for ((index, valueParameter) in firMethod.valueParameters.withIndex()) {
|
||||
newValueParameterTypeRefs += enhanceValueParameterType(
|
||||
firMethod, memberContext, predefinedEnhancementInfo, valueParameter as FirJavaValueParameter, index
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
val symbol = FirFunctionSymbol(original.callableId)
|
||||
with(firMethod) {
|
||||
FirMemberFunctionImpl(
|
||||
session, null, symbol, name,
|
||||
newReceiverTypeRef, newReturnTypeRef
|
||||
).apply {
|
||||
status = firMethod.status
|
||||
annotations += firMethod.annotations
|
||||
valueParameters += firMethod.valueParameters.zip(newValueParameterTypeRefs) { valueParameter, newTypeRef ->
|
||||
with(valueParameter) {
|
||||
FirValueParameterImpl(
|
||||
session, psi,
|
||||
this.name, newTypeRef,
|
||||
defaultValue, isCrossinline, isNoinline, isVararg
|
||||
).apply {
|
||||
annotations += valueParameter.annotations
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return symbol
|
||||
}
|
||||
|
||||
private fun FirJavaMethod.computeJvmDescriptor(): String = buildString {
|
||||
append(name.asString()) // TODO: Java constructors
|
||||
|
||||
append("(")
|
||||
for (parameter in valueParameters) {
|
||||
// TODO: appendErasedType(parameter.returnTypeRef)
|
||||
}
|
||||
append(")")
|
||||
|
||||
if ((returnTypeRef as FirJavaTypeRef).isVoid()) {
|
||||
append("V")
|
||||
} else {
|
||||
// TODO: appendErasedType(returnTypeRef)
|
||||
}
|
||||
}
|
||||
|
||||
private fun FirJavaTypeRef.isVoid(): Boolean {
|
||||
return type is JavaPrimitiveType && type.type == null
|
||||
}
|
||||
|
||||
// ================================================================================================
|
||||
|
||||
private fun enhanceReceiverType(
|
||||
ownerFunction: FirJavaMethod,
|
||||
memberContext: FirJavaEnhancementContext
|
||||
): FirResolvedTypeRef {
|
||||
val signatureParts = ownerFunction.partsForValueParameter(
|
||||
typeQualifierResolver,
|
||||
// TODO: check me
|
||||
parameterContainer = ownerFunction,
|
||||
methodContext = memberContext
|
||||
) {
|
||||
it.receiverTypeRef!!
|
||||
}.enhance(jsr305State)
|
||||
return signatureParts.type
|
||||
}
|
||||
|
||||
private val FirTypedDeclaration.valueParameters: List<FirValueParameter> get() = (this as? FirFunction)?.valueParameters.orEmpty()
|
||||
|
||||
private fun enhanceValueParameterType(
|
||||
ownerFunction: FirJavaMethod,
|
||||
memberContext: FirJavaEnhancementContext,
|
||||
predefinedEnhancementInfo: PredefinedFunctionEnhancementInfo?,
|
||||
ownerParameter: FirJavaValueParameter,
|
||||
index: Int
|
||||
): FirResolvedTypeRef {
|
||||
val signatureParts = ownerFunction.partsForValueParameter(
|
||||
typeQualifierResolver,
|
||||
parameterContainer = ownerParameter,
|
||||
methodContext = memberContext
|
||||
) {
|
||||
it.valueParameters[index].returnTypeRef
|
||||
}.enhance(jsr305State, predefinedEnhancementInfo?.parametersInfo?.getOrNull(index))
|
||||
return signatureParts.type
|
||||
}
|
||||
|
||||
private fun enhanceReturnType(
|
||||
ownerFunction: FirJavaMethod,
|
||||
memberContext: FirJavaEnhancementContext,
|
||||
predefinedEnhancementInfo: PredefinedFunctionEnhancementInfo?
|
||||
): FirResolvedTypeRef {
|
||||
val signatureParts = ownerFunction.parts(
|
||||
typeQualifierResolver,
|
||||
typeContainer = ownerFunction, isCovariant = true,
|
||||
containerContext = memberContext,
|
||||
containerApplicabilityType =
|
||||
if (false) // TODO: this.safeAs<FirProperty>()?.isJavaField == true
|
||||
AnnotationTypeQualifierResolver.QualifierApplicabilityType.FIELD
|
||||
else
|
||||
AnnotationTypeQualifierResolver.QualifierApplicabilityType.METHOD_RETURN_TYPE
|
||||
) { it.returnTypeRef }.enhance(jsr305State, predefinedEnhancementInfo?.returnTypeInfo)
|
||||
return signatureParts.type
|
||||
}
|
||||
|
||||
private fun FirCallableMember.partsForValueParameter(
|
||||
typeQualifierResolver: FirAnnotationTypeQualifierResolver,
|
||||
// TODO: investigate if it's really can be a null (check properties' with extension overrides in Java)
|
||||
parameterContainer: FirAnnotationContainer?,
|
||||
methodContext: FirJavaEnhancementContext,
|
||||
collector: (FirCallableMember) -> FirTypeRef
|
||||
) = parts(
|
||||
typeQualifierResolver,
|
||||
parameterContainer, false,
|
||||
parameterContainer?.let {
|
||||
methodContext.copyWithNewDefaultTypeQualifiers(typeQualifierResolver, jsr305State, it.annotations)
|
||||
} ?: methodContext,
|
||||
AnnotationTypeQualifierResolver.QualifierApplicabilityType.VALUE_PARAMETER,
|
||||
collector
|
||||
)
|
||||
|
||||
private val overriddenMemberCache = mutableMapOf<FirCallableMember, List<FirCallableMember>>()
|
||||
|
||||
private fun FirCallableMember.overriddenMembers(): List<FirCallableMember> {
|
||||
return overriddenMemberCache.getOrPut(this) {
|
||||
val result = mutableListOf<FirCallableMember>()
|
||||
if (this is FirNamedFunction) {
|
||||
val superTypesScope = useSiteScope.superTypesScope
|
||||
superTypesScope.processFunctionsByName(this.name) { basicFunctionSymbol ->
|
||||
val overriddenBy = with(useSiteScope) {
|
||||
basicFunctionSymbol.getOverridden(setOf(this@overriddenMembers.symbol as ConeFunctionSymbol))
|
||||
}
|
||||
val overriddenByFir = (overriddenBy as? FirFunctionSymbol)?.fir
|
||||
if (overriddenByFir === this@overriddenMembers) {
|
||||
result += (basicFunctionSymbol as FirFunctionSymbol).fir
|
||||
}
|
||||
ProcessorAction.NEXT
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
private fun FirCallableMember.parts(
|
||||
typeQualifierResolver: FirAnnotationTypeQualifierResolver,
|
||||
typeContainer: FirAnnotationContainer?,
|
||||
isCovariant: Boolean,
|
||||
containerContext: FirJavaEnhancementContext,
|
||||
containerApplicabilityType: AnnotationTypeQualifierResolver.QualifierApplicabilityType,
|
||||
collector: (FirCallableMember) -> FirTypeRef
|
||||
): EnhancementSignatureParts {
|
||||
return EnhancementSignatureParts(
|
||||
typeQualifierResolver,
|
||||
typeContainer,
|
||||
collector(this) as FirJavaTypeRef,
|
||||
this.overriddenMembers().map {
|
||||
collector(it)
|
||||
},
|
||||
isCovariant,
|
||||
// recompute default type qualifiers using type annotations
|
||||
containerContext.copyWithNewDefaultTypeQualifiers(
|
||||
typeQualifierResolver, jsr305State, collector(this).annotations
|
||||
),
|
||||
containerApplicabilityType
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.fir.java.scopes
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirNamedFunction
|
||||
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||
import org.jetbrains.kotlin.fir.java.toNotNullConeKotlinType
|
||||
import org.jetbrains.kotlin.fir.scopes.FirScope
|
||||
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.FirAbstractProviderBasedScope
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.FirClassDeclaredMemberScope
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
class JavaClassUseSiteScope(
|
||||
klass: FirRegularClass,
|
||||
session: FirSession,
|
||||
internal val superTypesScope: FirScope,
|
||||
private val declaredMemberScope: FirClassDeclaredMemberScope
|
||||
) : FirAbstractProviderBasedScope(session, lookupInFir = true) {
|
||||
internal val symbol = klass.symbol
|
||||
|
||||
//base symbol as key, overridden as value
|
||||
private val overriddenByBase = mutableMapOf<ConeFunctionSymbol, ConeFunctionSymbol?>()
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
private fun isSubtypeOf(subType: ConeKotlinType, superType: ConeKotlinType): Boolean {
|
||||
// TODO: introduce normal sub-typing
|
||||
return true
|
||||
}
|
||||
|
||||
private fun isSubtypeOf(subType: FirTypeRef, superType: FirTypeRef) =
|
||||
isSubtypeOf(subType.toNotNullConeKotlinType(), superType.toNotNullConeKotlinType())
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
private fun isEqualTypes(a: ConeKotlinType, b: ConeKotlinType): Boolean {
|
||||
// TODO: introduce normal type comparison
|
||||
return true
|
||||
}
|
||||
|
||||
private fun isEqualTypes(a: FirTypeRef, b: FirTypeRef) =
|
||||
isEqualTypes(a.toNotNullConeKotlinType(), b.toNotNullConeKotlinType())
|
||||
|
||||
private fun isOverriddenFunCheck(member: FirNamedFunction, self: FirNamedFunction): Boolean {
|
||||
return member.valueParameters.size == self.valueParameters.size &&
|
||||
member.valueParameters.zip(self.valueParameters).all { (memberParam, selfParam) ->
|
||||
isEqualTypes(memberParam.returnTypeRef, selfParam.returnTypeRef)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun ConeFunctionSymbol.getOverridden(candidates: Set<ConeFunctionSymbol>): ConeCallableSymbol? {
|
||||
if (overriddenByBase.containsKey(this)) return overriddenByBase[this]
|
||||
|
||||
fun sameReceivers(memberTypeRef: FirTypeRef?, selfTypeRef: FirTypeRef?): Boolean {
|
||||
return when {
|
||||
memberTypeRef != null && selfTypeRef != null -> isEqualTypes(memberTypeRef, selfTypeRef)
|
||||
else -> memberTypeRef == null && selfTypeRef == null
|
||||
}
|
||||
}
|
||||
|
||||
val self = (this as FirFunctionSymbol).fir as FirNamedFunction
|
||||
val overriding = candidates.firstOrNull {
|
||||
val member = (it as FirFunctionSymbol).fir as FirNamedFunction
|
||||
self.modality != Modality.FINAL
|
||||
&& sameReceivers(member.receiverTypeRef, self.receiverTypeRef)
|
||||
&& isSubtypeOf(member.returnTypeRef, self.returnTypeRef)
|
||||
&& isOverriddenFunCheck(member, self)
|
||||
} // TODO: two or more overrides for one fun?
|
||||
overriddenByBase[this] = overriding
|
||||
return overriding
|
||||
}
|
||||
|
||||
override fun processFunctionsByName(name: Name, processor: (ConeFunctionSymbol) -> ProcessorAction): ProcessorAction {
|
||||
val overrideCandidates = mutableSetOf<ConeFunctionSymbol>()
|
||||
if (!declaredMemberScope.processFunctionsByName(name) {
|
||||
overrideCandidates += it
|
||||
processor(it)
|
||||
}
|
||||
) return ProcessorAction.STOP
|
||||
|
||||
return superTypesScope.processFunctionsByName(name) {
|
||||
|
||||
val overriddenBy = it.getOverridden(overrideCandidates)
|
||||
if (overriddenBy == null) {
|
||||
processor(it)
|
||||
} else {
|
||||
ProcessorAction.NEXT
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.fir.java.scopes
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||
import org.jetbrains.kotlin.fir.java.declarations.FirJavaClass
|
||||
import org.jetbrains.kotlin.fir.resolve.FirScopeProvider
|
||||
import org.jetbrains.kotlin.fir.scopes.FirScope
|
||||
|
||||
class JavaFirScopeProvider : FirScopeProvider {
|
||||
override fun getDeclaredMemberScope(klass: FirRegularClass, session: FirSession): FirScope {
|
||||
if (klass !is FirJavaClass) return FirScopeProvider.emptyScope
|
||||
|
||||
return JavaClassEnhancementScope(session, klass.useSiteScope)
|
||||
}
|
||||
}
|
||||
@@ -6,9 +6,7 @@
|
||||
package org.jetbrains.kotlin.fir
|
||||
|
||||
import org.jetbrains.kotlin.analyzer.ModuleInfo
|
||||
import org.jetbrains.kotlin.fir.resolve.FirProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.FirQualifierResolver
|
||||
import org.jetbrains.kotlin.fir.resolve.FirTypeResolver
|
||||
import org.jetbrains.kotlin.fir.resolve.*
|
||||
import org.jetbrains.kotlin.fir.resolve.impl.*
|
||||
|
||||
abstract class FirModuleBasedSession(override val moduleInfo: ModuleInfo) : FirSessionBase() {
|
||||
@@ -19,3 +17,4 @@ abstract class FirModuleBasedSession(override val moduleInfo: ModuleInfo) : FirS
|
||||
registerComponent(FirTypeResolver::class, FirTypeResolverImpl(this))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+14
@@ -8,6 +8,8 @@ package org.jetbrains.kotlin.fir.resolve
|
||||
import org.jetbrains.kotlin.fir.symbols.CallableId
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||
import org.jetbrains.kotlin.fir.visitors.FirTransformer
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
@@ -38,4 +40,16 @@ abstract class AbstractFirSymbolProvider : FirSymbolProvider {
|
||||
calculated.first
|
||||
}
|
||||
}
|
||||
|
||||
fun <D> transformTopLevelClasses(transformer: FirTransformer<D>, data: D) {
|
||||
val symbols = classCache.values.filterNotNullTo(mutableListOf())
|
||||
// TODO: do something with new symbols which can be found during transformation of another symbols
|
||||
for (symbol in symbols) {
|
||||
if (symbol !is FirClassSymbol) continue
|
||||
if (symbol.classId.relativeClassName.parent().isRoot) {
|
||||
// Launch for top-level classes only
|
||||
symbol.fir.transform(transformer, data)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.fir.resolve
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||
import org.jetbrains.kotlin.fir.scopes.FirScope
|
||||
|
||||
interface FirScopeProvider {
|
||||
fun getDeclaredMemberScope(klass: FirRegularClass, session: FirSession): FirScope
|
||||
|
||||
companion object {
|
||||
val emptyScope = object : FirScope {}
|
||||
}
|
||||
}
|
||||
@@ -45,7 +45,7 @@ fun ConeClassifierLookupTag.toSymbol(useSiteSession: FirSession): ConeClassifier
|
||||
}
|
||||
|
||||
|
||||
fun ConeClassifierSymbol.constructType(typeArguments: Array<ConeKotlinTypeProjection>, isNullable: Boolean): ConeKotlinType {
|
||||
fun ConeClassifierSymbol.constructType(typeArguments: Array<ConeKotlinTypeProjection>, isNullable: Boolean): ConeLookupTagBasedType {
|
||||
return when (this) {
|
||||
is ConeTypeParameterSymbol -> {
|
||||
ConeTypeParameterTypeImpl(this, isNullable)
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.fir.resolve
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||
import org.jetbrains.kotlin.fir.declarations.expandedConeType
|
||||
import org.jetbrains.kotlin.fir.declarations.superConeTypes
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeClassifierSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol
|
||||
import org.jetbrains.kotlin.fir.types.ConeAbbreviatedType
|
||||
import org.jetbrains.kotlin.fir.types.ConeClassErrorType
|
||||
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
||||
|
||||
fun lookupSuperTypes(
|
||||
klass: FirRegularClass,
|
||||
lookupInterfaces: Boolean,
|
||||
deep: Boolean,
|
||||
useSiteSession: FirSession
|
||||
): List<ConeClassLikeType> {
|
||||
return mutableListOf<ConeClassLikeType>().also {
|
||||
if (lookupInterfaces) klass.symbol.collectSuperTypes(it, deep, useSiteSession)
|
||||
else klass.symbol.collectSuperClasses(it, useSiteSession)
|
||||
}
|
||||
}
|
||||
|
||||
private tailrec fun ConeClassLikeType.computePartialExpansion(useSiteSession: FirSession): ConeClassLikeType? {
|
||||
return when (this) {
|
||||
is ConeAbbreviatedType -> directExpansionType(useSiteSession)?.computePartialExpansion(useSiteSession)
|
||||
else -> this
|
||||
}
|
||||
}
|
||||
|
||||
private tailrec fun ConeClassifierSymbol.collectSuperClasses(
|
||||
list: MutableList<ConeClassLikeType>,
|
||||
useSiteSession: FirSession
|
||||
) {
|
||||
when (this) {
|
||||
is FirClassSymbol -> {
|
||||
val superClassType =
|
||||
fir.superConeTypes
|
||||
.map { it.computePartialExpansion(useSiteSession) }
|
||||
.firstOrNull {
|
||||
it !is ConeClassErrorType &&
|
||||
(it?.lookupTag?.toSymbol(useSiteSession) as? FirClassSymbol)?.fir?.classKind == ClassKind.CLASS
|
||||
} ?: return
|
||||
list += superClassType
|
||||
superClassType.lookupTag.toSymbol(useSiteSession)?.collectSuperClasses(list, useSiteSession)
|
||||
}
|
||||
is FirTypeAliasSymbol -> {
|
||||
val expansion = fir.expandedConeType?.computePartialExpansion(useSiteSession) ?: return
|
||||
expansion.lookupTag.toSymbol(useSiteSession)?.collectSuperClasses(list, useSiteSession)
|
||||
}
|
||||
else -> error("?!id:1")
|
||||
}
|
||||
}
|
||||
|
||||
private fun ConeClassifierSymbol.collectSuperTypes(
|
||||
list: MutableList<ConeClassLikeType>,
|
||||
deep: Boolean,
|
||||
useSiteSession: FirSession
|
||||
) {
|
||||
when (this) {
|
||||
is FirClassSymbol -> {
|
||||
val superClassTypes =
|
||||
fir.superConeTypes.mapNotNull { it.computePartialExpansion(useSiteSession) }
|
||||
list += superClassTypes
|
||||
if (deep)
|
||||
superClassTypes.forEach {
|
||||
if (it !is ConeClassErrorType) {
|
||||
it.lookupTag.toSymbol(useSiteSession)?.collectSuperTypes(list, deep, useSiteSession)
|
||||
}
|
||||
}
|
||||
}
|
||||
is FirTypeAliasSymbol -> {
|
||||
val expansion = fir.expandedConeType?.computePartialExpansion(useSiteSession) ?: return
|
||||
expansion.lookupTag.toSymbol(useSiteSession)?.collectSuperTypes(list, deep, useSiteSession)
|
||||
}
|
||||
else -> error("?!id:1")
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.fir.resolve.impl
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||
import org.jetbrains.kotlin.fir.resolve.FirScopeProvider
|
||||
import org.jetbrains.kotlin.fir.scopes.FirScope
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.FirCompositeScope
|
||||
|
||||
class FirCompositeScopeProvider(private val providers: List<FirScopeProvider>) : FirScopeProvider {
|
||||
override fun getDeclaredMemberScope(klass: FirRegularClass, session: FirSession): FirScope {
|
||||
return FirCompositeScope(providers.mapTo(mutableListOf()) { it.getDeclaredMemberScope(klass, session) })
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.fir.resolve.impl
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||
import org.jetbrains.kotlin.fir.declarations.impl.FirClassImpl
|
||||
import org.jetbrains.kotlin.fir.resolve.FirScopeProvider
|
||||
import org.jetbrains.kotlin.fir.scopes.FirScope
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.FirClassDeclaredMemberScope
|
||||
|
||||
class FirRegularScopeProvider : FirScopeProvider {
|
||||
override fun getDeclaredMemberScope(klass: FirRegularClass, session: FirSession): FirScope {
|
||||
if (klass !is FirClassImpl) return FirScopeProvider.emptyScope
|
||||
|
||||
return FirClassDeclaredMemberScope(klass, session)
|
||||
}
|
||||
|
||||
}
|
||||
-82
@@ -5,23 +5,9 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.resolve.transformers
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||
import org.jetbrains.kotlin.fir.declarations.expandedConeType
|
||||
import org.jetbrains.kotlin.fir.declarations.superConeTypes
|
||||
import org.jetbrains.kotlin.fir.resolve.directExpansionType
|
||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.FirCompositeScope
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.FirMemberTypeParameterScope
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeClassifierSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol
|
||||
import org.jetbrains.kotlin.fir.types.ConeAbbreviatedType
|
||||
import org.jetbrains.kotlin.fir.types.ConeClassErrorType
|
||||
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
abstract class FirAbstractTreeTransformerWithSuperTypes(reversedScopePriority: Boolean) : FirAbstractTreeTransformer() {
|
||||
protected val towerScope = FirCompositeScope(mutableListOf(), reversedPriority = reversedScopePriority)
|
||||
@@ -37,74 +23,6 @@ abstract class FirAbstractTreeTransformerWithSuperTypes(reversedScopePriority: B
|
||||
return result
|
||||
}
|
||||
|
||||
protected fun lookupSuperTypes(
|
||||
klass: FirRegularClass,
|
||||
lookupInterfaces: Boolean,
|
||||
deep: Boolean,
|
||||
useSiteSession: FirSession
|
||||
): List<ConeClassLikeType> {
|
||||
return mutableListOf<ConeClassLikeType>().also {
|
||||
if (lookupInterfaces) klass.symbol.collectSuperTypes(it, deep, useSiteSession)
|
||||
else klass.symbol.collectSuperClasses(it, useSiteSession)
|
||||
}
|
||||
}
|
||||
|
||||
private tailrec fun ConeClassLikeType.computePartialExpansion(useSiteSession: FirSession): ConeClassLikeType? {
|
||||
return when (this) {
|
||||
is ConeAbbreviatedType -> directExpansionType(useSiteSession)?.computePartialExpansion(useSiteSession)
|
||||
else -> this
|
||||
}
|
||||
}
|
||||
|
||||
private tailrec fun ConeClassifierSymbol.collectSuperClasses(
|
||||
list: MutableList<ConeClassLikeType>,
|
||||
useSiteSession: FirSession
|
||||
) {
|
||||
when (this) {
|
||||
is FirClassSymbol -> {
|
||||
val superClassType =
|
||||
fir.superConeTypes
|
||||
.map { it.computePartialExpansion(useSiteSession) }
|
||||
.firstOrNull {
|
||||
it !is ConeClassErrorType &&
|
||||
(it?.lookupTag?.toSymbol(useSiteSession) as? FirClassSymbol)?.fir?.classKind == ClassKind.CLASS
|
||||
} ?: return
|
||||
list += superClassType
|
||||
superClassType.lookupTag.toSymbol(useSiteSession)?.collectSuperClasses(list, useSiteSession)
|
||||
}
|
||||
is FirTypeAliasSymbol -> {
|
||||
val expansion = fir.expandedConeType?.computePartialExpansion(useSiteSession) ?: return
|
||||
expansion.lookupTag.toSymbol(useSiteSession)?.collectSuperClasses(list, useSiteSession)
|
||||
}
|
||||
else -> error("?!id:1")
|
||||
}
|
||||
}
|
||||
|
||||
private fun ConeClassifierSymbol.collectSuperTypes(
|
||||
list: MutableList<ConeClassLikeType>,
|
||||
deep: Boolean,
|
||||
useSiteSession: FirSession
|
||||
) {
|
||||
when (this) {
|
||||
is FirClassSymbol -> {
|
||||
val superClassTypes =
|
||||
fir.superConeTypes.mapNotNull { it.computePartialExpansion(useSiteSession) }
|
||||
list += superClassTypes
|
||||
if (deep)
|
||||
superClassTypes.forEach {
|
||||
if (it !is ConeClassErrorType) {
|
||||
it.lookupTag.toSymbol(useSiteSession)?.collectSuperTypes(list, deep, useSiteSession)
|
||||
}
|
||||
}
|
||||
}
|
||||
is FirTypeAliasSymbol -> {
|
||||
val expansion = fir.expandedConeType?.computePartialExpansion(useSiteSession) ?: return
|
||||
expansion.lookupTag.toSymbol(useSiteSession)?.collectSuperTypes(list, deep, useSiteSession)
|
||||
}
|
||||
else -> error("?!id:1")
|
||||
}
|
||||
}
|
||||
|
||||
protected fun FirMemberDeclaration.addTypeParametersScope() {
|
||||
val scopes = towerScope.scopes
|
||||
if (typeParameters.isNotEmpty()) {
|
||||
|
||||
+4
-1
@@ -14,10 +14,13 @@ import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
|
||||
import org.jetbrains.kotlin.fir.references.FirResolvedCallableReferenceImpl
|
||||
import org.jetbrains.kotlin.fir.resolve.FirScopeProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.lookupSuperTypes
|
||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
|
||||
import org.jetbrains.kotlin.fir.scopes.ProcessorAction.NEXT
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.*
|
||||
import org.jetbrains.kotlin.fir.service
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||
@@ -53,7 +56,7 @@ class FirAccessResolveTransformer : FirAbstractTreeTransformerWithSuperTypes(rev
|
||||
|
||||
private fun FirRegularClass.buildUseSiteScope(useSiteSession: FirSession = session): FirClassUseSiteScope {
|
||||
val superTypeScope = FirCompositeScope(mutableListOf())
|
||||
val declaredScope = FirClassDeclaredMemberScope(this, useSiteSession)
|
||||
val declaredScope = useSiteSession.service<FirScopeProvider>().getDeclaredMemberScope(this, useSiteSession)
|
||||
lookupSuperTypes(this, lookupInterfaces = true, deep = false, useSiteSession = useSiteSession)
|
||||
.mapNotNullTo(superTypeScope.scopes) { useSiteSuperType ->
|
||||
if (useSiteSuperType is ConeClassErrorType) return@mapNotNullTo null
|
||||
|
||||
+1
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.render
|
||||
import org.jetbrains.kotlin.fir.resolve.FirProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.lookupSuperTypes
|
||||
import org.jetbrains.kotlin.fir.scopes.FirPosition
|
||||
import org.jetbrains.kotlin.fir.scopes.addImportingScopes
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.*
|
||||
|
||||
+1
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.resolve.FirProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.lookupSuperTypes
|
||||
import org.jetbrains.kotlin.fir.scopes.FirPosition
|
||||
import org.jetbrains.kotlin.fir.scopes.addImportingScopes
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.*
|
||||
|
||||
+2
-1
@@ -11,7 +11,8 @@ import org.jetbrains.kotlin.fir.resolve.impl.FirCompositeSymbolProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.impl.FirDependenciesSymbolProviderImpl
|
||||
import org.jetbrains.kotlin.fir.scopes.FirScope
|
||||
|
||||
abstract class FirAbstractProviderBasedScope(val session: FirSession, lookupInFir: Boolean = true) : FirScope {
|
||||
abstract class FirAbstractProviderBasedScope(val session: FirSession, lookupInFir: Boolean = true) :
|
||||
FirScope {
|
||||
val provider = when (val symbolProvider = FirSymbolProvider.getInstance(session)) {
|
||||
is FirCompositeSymbolProvider -> symbolProvider.takeIf { !lookupInFir }?.providers?.find {
|
||||
it is FirDependenciesSymbolProviderImpl
|
||||
|
||||
@@ -56,6 +56,10 @@ class FirRenderer(builder: StringBuilder) : FirVisitorVoid() {
|
||||
printer.popIndent()
|
||||
}
|
||||
|
||||
fun newLine() {
|
||||
println()
|
||||
}
|
||||
|
||||
override fun visitElement(element: FirElement) {
|
||||
element.acceptChildren(this)
|
||||
}
|
||||
@@ -214,22 +218,32 @@ class FirRenderer(builder: StringBuilder) : FirVisitorVoid() {
|
||||
}
|
||||
|
||||
private fun FirDeclarationContainer.renderDeclarations() {
|
||||
renderInBraces {
|
||||
for (declaration in declarations) {
|
||||
declaration.accept(this@FirRenderer)
|
||||
println()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun renderInBraces(f: () -> Unit) {
|
||||
println(" {")
|
||||
pushIndent()
|
||||
for (declaration in declarations) {
|
||||
declaration.accept(this@FirRenderer)
|
||||
println()
|
||||
}
|
||||
f()
|
||||
popIndent()
|
||||
println("}")
|
||||
}
|
||||
|
||||
override fun visitRegularClass(regularClass: FirRegularClass) {
|
||||
visitMemberDeclaration(regularClass)
|
||||
fun renderSupertypes(regularClass: FirRegularClass) {
|
||||
if (regularClass.superTypeRefs.isNotEmpty()) {
|
||||
print(" : ")
|
||||
regularClass.superTypeRefs.renderSeparated()
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitRegularClass(regularClass: FirRegularClass) {
|
||||
visitMemberDeclaration(regularClass)
|
||||
renderSupertypes(regularClass)
|
||||
regularClass.renderDeclarations()
|
||||
}
|
||||
|
||||
@@ -345,14 +359,12 @@ class FirRenderer(builder: StringBuilder) : FirVisitorVoid() {
|
||||
}
|
||||
|
||||
override fun visitBlock(block: FirBlock) {
|
||||
println(" {")
|
||||
pushIndent()
|
||||
for (statement in block.statements) {
|
||||
statement.accept(this)
|
||||
println()
|
||||
renderInBraces {
|
||||
for (statement in block.statements) {
|
||||
statement.accept(this)
|
||||
println()
|
||||
}
|
||||
}
|
||||
popIndent()
|
||||
println("}")
|
||||
}
|
||||
|
||||
override fun visitTypeAlias(typeAlias: FirTypeAlias) {
|
||||
@@ -657,8 +669,10 @@ class FirRenderer(builder: StringBuilder) : FirVisitorVoid() {
|
||||
buildString {
|
||||
append("ft<")
|
||||
append(lowerBound.asString())
|
||||
append(lowerBound.nullability.suffix)
|
||||
append(", ")
|
||||
append(upperBound.asString())
|
||||
append(upperBound.nullability.suffix)
|
||||
append(">")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlin.fir
|
||||
|
||||
import org.jetbrains.kotlin.analyzer.ModuleInfo
|
||||
import org.jetbrains.kotlin.utils.Jsr305State
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
interface FirSession {
|
||||
@@ -13,6 +14,8 @@ interface FirSession {
|
||||
|
||||
val sessionProvider: FirSessionProvider? get() = null
|
||||
|
||||
val jsr305State: Jsr305State? get() = null
|
||||
|
||||
val components: Map<KClass<*>, Any>
|
||||
|
||||
fun <T : Any> getService(kclass: KClass<T>): T =
|
||||
|
||||
@@ -29,6 +29,30 @@ fun <T : FirElement, D> MutableList<T>.transformInplace(transformer: FirTransfor
|
||||
}
|
||||
}
|
||||
|
||||
fun <T : FirElement, D> MutableList<T>.transformInplaceWithBeforeOperation(
|
||||
transformer: FirTransformer<D>, data: D, operation: (T, Int) -> Unit
|
||||
) {
|
||||
val iterator = this.listIterator()
|
||||
var index = 0
|
||||
while (iterator.hasNext()) {
|
||||
val next = iterator.next()
|
||||
operation(next, index++)
|
||||
val result = next.transform<T, D>(transformer, data)
|
||||
if (result.isSingle) {
|
||||
iterator.set(result.single)
|
||||
} else {
|
||||
val resultIterator = result.list.listIterator()
|
||||
if (!resultIterator.hasNext()) {
|
||||
iterator.remove()
|
||||
} else {
|
||||
iterator.set(resultIterator.next())
|
||||
}
|
||||
while (resultIterator.hasNext()) {
|
||||
iterator.add(resultIterator.next())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun <T : FirElement, D> T.transformSingle(transformer: FirTransformer<D>, data: D): T {
|
||||
return this.transform<T, D>(transformer, data).single
|
||||
|
||||
@@ -7,8 +7,11 @@ package org.jetbrains.kotlin.fir.expressions
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
|
||||
import org.jetbrains.kotlin.fir.BaseTransformedType
|
||||
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
||||
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||
import org.jetbrains.kotlin.fir.visitors.FirVisitor
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
@BaseTransformedType
|
||||
interface FirAnnotationCall : FirCall {
|
||||
@@ -24,4 +27,7 @@ interface FirAnnotationCall : FirCall {
|
||||
annotationTypeRef.accept(visitor, data)
|
||||
super.acceptChildren(visitor, data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val FirAnnotationCall.resolvedFqName: FqName?
|
||||
get() = ((annotationTypeRef as? FirResolvedTypeRef)?.type as? ConeClassLikeType)?.lookupTag?.classId?.asSingleFqName()
|
||||
|
||||
@@ -5,9 +5,19 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.expressions
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirResolvedCallableReference
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.visitors.FirVisitor
|
||||
|
||||
interface FirExpression : FirStatement {
|
||||
override fun <R, D> accept(visitor: FirVisitor<R, D>, data: D): R =
|
||||
visitor.visitExpression(this, data)
|
||||
}
|
||||
|
||||
fun FirExpression.toResolvedCallableReference(): FirResolvedCallableReference? {
|
||||
return (this as? FirQualifiedAccess)?.calleeReference as? FirResolvedCallableReference
|
||||
}
|
||||
|
||||
fun FirExpression.toResolvedCallableSymbol(): ConeCallableSymbol? {
|
||||
return toResolvedCallableReference()?.callableSymbol
|
||||
}
|
||||
@@ -213,14 +213,22 @@ object JavaToKotlinClassMap : PlatformToKotlinClassMap {
|
||||
emptySet<ClassDescriptor>()
|
||||
}
|
||||
|
||||
fun isMutable(mutable: ClassDescriptor): Boolean = mutableToReadOnly.containsKey(DescriptorUtils.getFqName(mutable))
|
||||
fun mutableToReadOnly(fqNameUnsafe: FqNameUnsafe?): FqName? = mutableToReadOnly[fqNameUnsafe]
|
||||
|
||||
fun readOnlyToMutable(fqNameUnsafe: FqNameUnsafe?): FqName? = readOnlyToMutable[fqNameUnsafe]
|
||||
|
||||
fun isMutable(fqNameUnsafe: FqNameUnsafe?): Boolean = mutableToReadOnly.containsKey(fqNameUnsafe)
|
||||
|
||||
fun isMutable(mutable: ClassDescriptor): Boolean = isMutable(DescriptorUtils.getFqName(mutable))
|
||||
|
||||
fun isMutable(type: KotlinType): Boolean {
|
||||
val classDescriptor = TypeUtils.getClassDescriptor(type)
|
||||
return classDescriptor != null && isMutable(classDescriptor)
|
||||
}
|
||||
|
||||
fun isReadOnly(readOnly: ClassDescriptor): Boolean = readOnlyToMutable.containsKey(DescriptorUtils.getFqName(readOnly))
|
||||
fun isReadOnly(fqNameUnsafe: FqNameUnsafe?): Boolean = readOnlyToMutable.containsKey(fqNameUnsafe)
|
||||
|
||||
fun isReadOnly(readOnly: ClassDescriptor): Boolean = isReadOnly(DescriptorUtils.getFqName(readOnly))
|
||||
|
||||
fun isReadOnly(type: KotlinType): Boolean {
|
||||
val classDescriptor = TypeUtils.getClassDescriptor(type)
|
||||
|
||||
+5
-5
@@ -34,13 +34,13 @@ import org.jetbrains.kotlin.utils.Jsr305State
|
||||
import org.jetbrains.kotlin.utils.ReportLevel
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
|
||||
|
||||
private val TYPE_QUALIFIER_NICKNAME_FQNAME = FqName("javax.annotation.meta.TypeQualifierNickname")
|
||||
private val TYPE_QUALIFIER_FQNAME = FqName("javax.annotation.meta.TypeQualifier")
|
||||
private val TYPE_QUALIFIER_DEFAULT_FQNAME = FqName("javax.annotation.meta.TypeQualifierDefault")
|
||||
val TYPE_QUALIFIER_NICKNAME_FQNAME = FqName("javax.annotation.meta.TypeQualifierNickname")
|
||||
val TYPE_QUALIFIER_FQNAME = FqName("javax.annotation.meta.TypeQualifier")
|
||||
val TYPE_QUALIFIER_DEFAULT_FQNAME = FqName("javax.annotation.meta.TypeQualifierDefault")
|
||||
|
||||
private val MIGRATION_ANNOTATION_FQNAME = FqName("kotlin.annotations.jvm.UnderMigration")
|
||||
val MIGRATION_ANNOTATION_FQNAME = FqName("kotlin.annotations.jvm.UnderMigration")
|
||||
|
||||
private val BUILT_IN_TYPE_QUALIFIER_DEFAULT_ANNOTATIONS = mapOf(
|
||||
val BUILT_IN_TYPE_QUALIFIER_DEFAULT_ANNOTATIONS = mapOf(
|
||||
FqName("javax.annotation.ParametersAreNullableByDefault") to
|
||||
NullabilityQualifierWithApplicability(
|
||||
NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NULLABLE),
|
||||
|
||||
@@ -93,9 +93,9 @@ interface JavaResolverSettings {
|
||||
}
|
||||
}
|
||||
|
||||
private typealias QualifierByApplicabilityType = EnumMap<AnnotationTypeQualifierResolver.QualifierApplicabilityType, NullabilityQualifierWithMigrationStatus?>
|
||||
typealias QualifierByApplicabilityType = EnumMap<AnnotationTypeQualifierResolver.QualifierApplicabilityType, NullabilityQualifierWithMigrationStatus?>
|
||||
|
||||
class JavaTypeQualifiersByElementType(internal val nullabilityQualifiers: QualifierByApplicabilityType) {
|
||||
class JavaTypeQualifiersByElementType(val nullabilityQualifiers: QualifierByApplicabilityType) {
|
||||
operator fun get(applicabilityType: AnnotationTypeQualifierResolver.QualifierApplicabilityType?): JavaTypeQualifiers? {
|
||||
val nullabilityQualifierWithMigrationStatus = nullabilityQualifiers[applicabilityType] ?: return null
|
||||
|
||||
|
||||
+3
-3
@@ -462,7 +462,7 @@ class SignatureEnhancement(
|
||||
}
|
||||
}
|
||||
|
||||
private fun createJavaTypeQualifiers(
|
||||
fun createJavaTypeQualifiers(
|
||||
nullability: NullabilityQualifier?,
|
||||
mutability: MutabilityQualifier?,
|
||||
forWarning: Boolean,
|
||||
@@ -474,7 +474,7 @@ private fun createJavaTypeQualifiers(
|
||||
return JavaTypeQualifiers(nullability, mutability, true, forWarning)
|
||||
}
|
||||
|
||||
private fun <T : Any> Set<T>.select(low: T, high: T, own: T?, isCovariant: Boolean): T? {
|
||||
fun <T : Any> Set<T>.select(low: T, high: T, own: T?, isCovariant: Boolean): T? {
|
||||
if (isCovariant) {
|
||||
val supertypeQualifier = if (low in this) low else if (high in this) high else null
|
||||
return if (supertypeQualifier == low && own == high) null else own ?: supertypeQualifier
|
||||
@@ -488,7 +488,7 @@ private fun <T : Any> Set<T>.select(low: T, high: T, own: T?, isCovariant: Boole
|
||||
return effectiveSet.singleOrNull()
|
||||
}
|
||||
|
||||
private fun Set<NullabilityQualifier>.select(own: NullabilityQualifier?, isCovariant: Boolean) =
|
||||
fun Set<NullabilityQualifier>.select(own: NullabilityQualifier?, isCovariant: Boolean) =
|
||||
if (own == NullabilityQualifier.FORCE_FLEXIBILITY)
|
||||
NullabilityQualifier.FORCE_FLEXIBILITY
|
||||
else
|
||||
|
||||
+2
-2
@@ -45,7 +45,7 @@ fun KotlinType.enhance(qualifiers: (Int) -> JavaTypeQualifiers) = unwrap().enhan
|
||||
fun KotlinType.hasEnhancedNullability()
|
||||
= annotations.findAnnotation(JvmAnnotationNames.ENHANCED_NULLABILITY_ANNOTATION) != null
|
||||
|
||||
private enum class TypeComponentPosition {
|
||||
enum class TypeComponentPosition {
|
||||
FLEXIBLE_LOWER,
|
||||
FLEXIBLE_UPPER,
|
||||
INFLEXIBLE
|
||||
@@ -147,7 +147,7 @@ private fun List<Annotations>.compositeAnnotationsOrSingle() = when (size) {
|
||||
else -> CompositeAnnotations(this.toList())
|
||||
}
|
||||
|
||||
private fun TypeComponentPosition.shouldEnhance() = this != TypeComponentPosition.INFLEXIBLE
|
||||
fun TypeComponentPosition.shouldEnhance() = this != TypeComponentPosition.INFLEXIBLE
|
||||
|
||||
private data class EnhancementResult<out T>(val result: T, val enhancementAnnotations: Annotations?)
|
||||
private fun <T> T.noChange() = EnhancementResult(this, null)
|
||||
|
||||
+5
-5
@@ -27,11 +27,11 @@ enum class MutabilityQualifier {
|
||||
MUTABLE
|
||||
}
|
||||
|
||||
class JavaTypeQualifiers internal constructor(
|
||||
val nullability: NullabilityQualifier?,
|
||||
val mutability: MutabilityQualifier?,
|
||||
internal val isNotNullTypeParameter: Boolean,
|
||||
internal val isNullabilityQualifierForWarning: Boolean = false
|
||||
class JavaTypeQualifiers(
|
||||
val nullability: NullabilityQualifier?,
|
||||
val mutability: MutabilityQualifier?,
|
||||
val isNotNullTypeParameter: Boolean,
|
||||
val isNullabilityQualifierForWarning: Boolean = false
|
||||
) {
|
||||
companion object {
|
||||
val NONE = JavaTypeQualifiers(null, null, false)
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
public open class Annotated : R|java/lang/Object| {
|
||||
@R|org/jetbrains/annotations/NotNull|() public open operator function foo(@R|org/jetbrains/annotations/Nullable|() param: R|ft<java/lang/String?, java/lang/String?>|?): R|ft<java/lang/String, java/lang/String>|
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class Annotated {
|
||||
@NotNull
|
||||
public String foo(@Nullable String param) {
|
||||
if (param != null) return param;
|
||||
else return "";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
class User : Annotated() {
|
||||
fun test() {
|
||||
val x = foo("123")
|
||||
val y = foo(null)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
FILE: jvm.kt
|
||||
public final class User : R|Annotated| {
|
||||
public constructor(): super<R|Annotated|>()
|
||||
|
||||
public final function test(): R|kotlin/Unit| {
|
||||
val x: R|error: Not supported: FirImplicitTypeRefImpl| = R|/Annotated.foo|(String(123))
|
||||
val y: R|error: Not supported: FirImplicitTypeRefImpl| = R|/Annotated.foo|(Null(null))
|
||||
}
|
||||
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
public open class Annotated : R|java/lang/Object| {
|
||||
@R|org/jetbrains/annotations/NotNull|() public open operator function foo(@R|org/jetbrains/annotations/Nullable|() param: R|ft<java/lang/String?, java/lang/String?>|?): R|ft<java/lang/String, java/lang/String>|
|
||||
|
||||
}
|
||||
public open class AnnotatedDerived : R|Annotated| {
|
||||
public open operator function foo(param: R|ft<java/lang/String?, java/lang/String?>|?): R|ft<java/lang/String, java/lang/String>|
|
||||
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class Annotated {
|
||||
@NotNull
|
||||
public String foo(@Nullable String param) {
|
||||
if (param != null) return param;
|
||||
else return "";
|
||||
}
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
public class AnnotatedDerived extends Annotated {
|
||||
public String foo(String param) {
|
||||
return super.foo(param);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
class User : AnnotatedDerived() {
|
||||
fun test() {
|
||||
val x = foo("123")
|
||||
val y = foo(null)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
FILE: jvm.kt
|
||||
public final class User : R|AnnotatedDerived| {
|
||||
public constructor(): super<R|AnnotatedDerived|>()
|
||||
|
||||
public final function test(): R|kotlin/Unit| {
|
||||
val x: R|error: Not supported: FirImplicitTypeRefImpl| = <Ambiguity: foo, [/AnnotatedDerived.foo, /Annotated.foo]>#(String(123))
|
||||
val y: R|error: Not supported: FirImplicitTypeRefImpl| = <Ambiguity: foo, [/AnnotatedDerived.foo, /Annotated.foo]>#(Null(null))
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
public open class Some : R|java/lang/Object| {
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
<T> public open class A : R|java/lang/Object| {
|
||||
public open operator function foo(t: R|ft<T, T?>|!): R|ft<T, T?>|!
|
||||
|
||||
}
|
||||
+1
-1
@@ -7,7 +7,7 @@ FILE: simpleFakeOverride.kt
|
||||
public constructor(): super<R|A<Some>|>()
|
||||
|
||||
public final function test(): R|kotlin/Unit| {
|
||||
R|FakeOverride</A.foo: R|ft<T, T>|!>|(<Unresolved name: Some>#())
|
||||
R|FakeOverride</A.foo: R|ft<T, T?>|!>|(<Unresolved name: Some>#())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
public open class Some : R|java/lang/Object| {
|
||||
public open operator function foo(param: R|kotlin/Int|): R|kotlin/Boolean|
|
||||
|
||||
public open operator function bar(arr: R|kotlin/IntArray|): R|kotlin/Array<ft<java/lang/String, java/lang/String?>>|
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
public class Some {
|
||||
public boolean foo(int param) {
|
||||
return param > 0;
|
||||
}
|
||||
|
||||
public String[] bar(int[] arr) {
|
||||
String[] result = new String[arr.length];
|
||||
int i = 0;
|
||||
for (int elem: arr) {
|
||||
result[i++] = elem;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
class A : Some() {
|
||||
fun test() {
|
||||
val res1 = foo(1)
|
||||
val res2 = foo(-1)
|
||||
val res3 = bar(intArrayOf(0, 2, -2))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
FILE: jvm.kt
|
||||
public final class A : R|Some| {
|
||||
public constructor(): super<R|Some|>()
|
||||
|
||||
public final function test(): R|kotlin/Unit| {
|
||||
val res1: R|error: Not supported: FirImplicitTypeRefImpl| = R|/Some.foo|(Int(1))
|
||||
val res2: R|error: Not supported: FirImplicitTypeRefImpl| = R|/Some.foo|(<Unresolved name: unaryMinus>#(Int(1)))
|
||||
val res3: R|error: Not supported: FirImplicitTypeRefImpl| = R|/Some.bar|(<Unresolved name: intArrayOf>#(Int(0), Int(2), <Unresolved name: unaryMinus>#(Int(2))))
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
public open class A : R|java/lang/Object| {
|
||||
public open operator function foo(): R|ft<A, A?>|!
|
||||
|
||||
public open operator function bar(): R|ft<A, A?>|!
|
||||
|
||||
}
|
||||
@@ -12,15 +12,26 @@ import com.intellij.psi.PsiManager
|
||||
import com.intellij.psi.search.FileTypeIndex
|
||||
import org.jetbrains.kotlin.fir.FirRenderer
|
||||
import org.jetbrains.kotlin.fir.builder.RawFirBuilder
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirFile
|
||||
import org.jetbrains.kotlin.fir.dependenciesWithoutSelf
|
||||
import org.jetbrains.kotlin.fir.java.FirJavaModuleBasedSession
|
||||
import org.jetbrains.kotlin.fir.java.FirLibrarySession
|
||||
import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider
|
||||
import org.jetbrains.kotlin.fir.java.JavaSymbolProvider
|
||||
import org.jetbrains.kotlin.fir.java.declarations.FirJavaClass
|
||||
import org.jetbrains.kotlin.fir.java.declarations.FirJavaMethod
|
||||
import org.jetbrains.kotlin.fir.java.scopes.JavaClassEnhancementScope
|
||||
import org.jetbrains.kotlin.fir.resolve.FirProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.FirScopeProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.impl.FirCompositeSymbolProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.impl.FirProviderImpl
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.FirTotalResolveTransformer
|
||||
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.FirCompositeScope
|
||||
import org.jetbrains.kotlin.fir.service
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
|
||||
import org.jetbrains.kotlin.idea.KotlinFileType
|
||||
import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo
|
||||
import org.jetbrains.kotlin.idea.caches.project.isLibraryClasses
|
||||
@@ -64,9 +75,11 @@ abstract class AbstractFirMultiModuleResolveTest : AbstractMultiModuleTest() {
|
||||
|
||||
private fun doFirResolveTest(dirPath: String) {
|
||||
val firFiles = mutableListOf<FirFile>()
|
||||
val sessions = mutableListOf<FirJavaModuleBasedSession>()
|
||||
val provider = FirProjectSessionProvider(project)
|
||||
for (module in project.allModules().drop(1)) {
|
||||
val session = createSession(module, provider)
|
||||
sessions += session
|
||||
|
||||
val builder = RawFirBuilder(session, stubMode = false)
|
||||
val psiManager = PsiManager.getInstance(project)
|
||||
@@ -112,5 +125,54 @@ abstract class AbstractFirMultiModuleResolveTest : AbstractMultiModuleTest() {
|
||||
val expectedPath = expectedTxtPath((file.psi as PsiFile).virtualFile)
|
||||
KotlinTestUtils.assertEqualsToFile(File(expectedPath), firFileDump)
|
||||
}
|
||||
val processedJavaClasses = mutableSetOf<FirJavaClass>()
|
||||
val javaFirDump = StringBuilder().also { builder ->
|
||||
val renderer = FirRenderer(builder)
|
||||
for (session in sessions) {
|
||||
val symbolProvider = session.service<FirSymbolProvider>() as FirCompositeSymbolProvider
|
||||
val javaProvider = symbolProvider.providers.filterIsInstance<JavaSymbolProvider>().first()
|
||||
for (javaClass in javaProvider.getJavaTopLevelClasses().sortedBy { it.name }) {
|
||||
if (javaClass !is FirJavaClass || javaClass in processedJavaClasses) continue
|
||||
val enhancementScope = session.service<FirScopeProvider>().getDeclaredMemberScope(javaClass, session).let {
|
||||
when (it) {
|
||||
is FirCompositeScope -> it.scopes.filterIsInstance<JavaClassEnhancementScope>().first()
|
||||
is JavaClassEnhancementScope -> it
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
if (enhancementScope == null) {
|
||||
javaClass.accept(renderer, null)
|
||||
} else {
|
||||
renderer.visitMemberDeclaration(javaClass)
|
||||
renderer.renderSupertypes(javaClass)
|
||||
renderer.renderInBraces {
|
||||
val renderedDeclarations = mutableListOf<FirDeclaration>()
|
||||
for (declaration in javaClass.declarations) {
|
||||
if (declaration in renderedDeclarations) continue
|
||||
if (declaration !is FirJavaMethod) {
|
||||
declaration.accept(renderer, null)
|
||||
renderer.newLine()
|
||||
renderedDeclarations += declaration
|
||||
} else {
|
||||
enhancementScope.processFunctionsByName(declaration.name) { symbol ->
|
||||
val enhanced = (symbol as? FirFunctionSymbol)?.fir
|
||||
if (enhanced != null && enhanced !in renderedDeclarations) {
|
||||
enhanced.accept(renderer, null)
|
||||
renderer.newLine()
|
||||
renderedDeclarations += enhanced
|
||||
}
|
||||
ProcessorAction.NEXT
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
processedJavaClasses += javaClass
|
||||
}
|
||||
}
|
||||
}.toString()
|
||||
if (javaFirDump.isNotEmpty()) {
|
||||
KotlinTestUtils.assertEqualsToFile(File("$dirPath/extraDump.java.txt"), javaFirDump)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+15
@@ -34,6 +34,16 @@ public class FirMultiModuleResolveTestGenerated extends AbstractFirMultiModuleRe
|
||||
runTest("idea/testData/fir/multiModule/basic/");
|
||||
}
|
||||
|
||||
@TestMetadata("basicWithAnnotatedJava")
|
||||
public void testBasicWithAnnotatedJava() throws Exception {
|
||||
runTest("idea/testData/fir/multiModule/basicWithAnnotatedJava/");
|
||||
}
|
||||
|
||||
@TestMetadata("basicWithAnnotatedOverriddenJava")
|
||||
public void testBasicWithAnnotatedOverriddenJava() throws Exception {
|
||||
runTest("idea/testData/fir/multiModule/basicWithAnnotatedOverriddenJava/");
|
||||
}
|
||||
|
||||
@TestMetadata("basicWithJava")
|
||||
public void testBasicWithJava() throws Exception {
|
||||
runTest("idea/testData/fir/multiModule/basicWithJava/");
|
||||
@@ -44,6 +54,11 @@ public class FirMultiModuleResolveTestGenerated extends AbstractFirMultiModuleRe
|
||||
runTest("idea/testData/fir/multiModule/basicWithJavaFakeOverride/");
|
||||
}
|
||||
|
||||
@TestMetadata("basicWithPrimitiveJava")
|
||||
public void testBasicWithPrimitiveJava() throws Exception {
|
||||
runTest("idea/testData/fir/multiModule/basicWithPrimitiveJava/");
|
||||
}
|
||||
|
||||
@TestMetadata("mppFakeOverrides")
|
||||
public void testMppFakeOverrides() throws Exception {
|
||||
runTest("idea/testData/fir/multiModule/mppFakeOverrides/");
|
||||
|
||||
Reference in New Issue
Block a user