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
|
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() {
|
class ConeKotlinErrorType(val reason: String) : ConeKotlinType() {
|
||||||
override val typeArguments: Array<out ConeKotlinTypeProjection>
|
override val typeArguments: Array<out ConeKotlinTypeProjection>
|
||||||
get() = EMPTY_ARRAY
|
get() = EMPTY_ARRAY
|
||||||
|
|||||||
@@ -9,11 +9,11 @@ import com.intellij.openapi.project.Project
|
|||||||
import com.intellij.psi.search.GlobalSearchScope
|
import com.intellij.psi.search.GlobalSearchScope
|
||||||
import org.jetbrains.kotlin.analyzer.ModuleInfo
|
import org.jetbrains.kotlin.analyzer.ModuleInfo
|
||||||
import org.jetbrains.kotlin.fir.*
|
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.FirProvider
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.FirScopeProvider
|
||||||
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
|
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
|
||||||
import org.jetbrains.kotlin.fir.resolve.impl.FirCompositeSymbolProvider
|
import org.jetbrains.kotlin.fir.resolve.impl.*
|
||||||
import org.jetbrains.kotlin.fir.resolve.impl.FirDependenciesSymbolProviderImpl
|
|
||||||
import org.jetbrains.kotlin.fir.resolve.impl.FirLibrarySymbolProviderImpl
|
|
||||||
|
|
||||||
class FirJavaModuleBasedSession(
|
class FirJavaModuleBasedSession(
|
||||||
moduleInfo: ModuleInfo,
|
moduleInfo: ModuleInfo,
|
||||||
@@ -21,7 +21,6 @@ class FirJavaModuleBasedSession(
|
|||||||
scope: GlobalSearchScope,
|
scope: GlobalSearchScope,
|
||||||
dependenciesProvider: FirSymbolProvider? = null
|
dependenciesProvider: FirSymbolProvider? = null
|
||||||
) : FirModuleBasedSession(moduleInfo) {
|
) : FirModuleBasedSession(moduleInfo) {
|
||||||
|
|
||||||
init {
|
init {
|
||||||
sessionProvider.sessionCache[moduleInfo] = this
|
sessionProvider.sessionCache[moduleInfo] = this
|
||||||
registerComponent(
|
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 com.intellij.psi.search.GlobalSearchScope
|
||||||
import org.jetbrains.kotlin.fir.FirSession
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirNamedFunction
|
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.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.FirJavaClass
|
||||||
import org.jetbrains.kotlin.fir.java.declarations.FirJavaMethod
|
import org.jetbrains.kotlin.fir.java.declarations.FirJavaMethod
|
||||||
import org.jetbrains.kotlin.fir.java.declarations.FirJavaValueParameter
|
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.AbstractFirSymbolProvider
|
||||||
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
|
import org.jetbrains.kotlin.fir.symbols.CallableId
|
||||||
import org.jetbrains.kotlin.fir.service
|
import org.jetbrains.kotlin.fir.symbols.ConeCallableSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.*
|
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
|
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.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.ClassId
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.resolve.jvm.KotlinJavaPsiFacade
|
import org.jetbrains.kotlin.resolve.jvm.KotlinJavaPsiFacade
|
||||||
import org.jetbrains.kotlin.types.Variance
|
|
||||||
|
|
||||||
class JavaSymbolProvider(
|
class JavaSymbolProvider(
|
||||||
val session: FirSession,
|
val session: FirSession,
|
||||||
@@ -49,149 +35,6 @@ class JavaSymbolProvider(
|
|||||||
|
|
||||||
private val facade: KotlinJavaPsiFacade get() = KotlinJavaPsiFacade.getInstance(project)
|
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)
|
private fun findClass(classId: ClassId): JavaClass? = facade.findClass(JavaClassFinder.Request(classId), searchScope)
|
||||||
|
|
||||||
override fun getCallableSymbols(callableId: CallableId): List<ConeCallableSymbol> {
|
override fun getCallableSymbols(callableId: CallableId): List<ConeCallableSymbol> {
|
||||||
@@ -201,39 +44,12 @@ class JavaSymbolProvider(
|
|||||||
?: return@lookupCacheOrCalculate emptyList()
|
?: return@lookupCacheOrCalculate emptyList()
|
||||||
val firClass = classSymbol.fir as FirModifiableClass
|
val firClass = classSymbol.fir as FirModifiableClass
|
||||||
val callableSymbols = mutableListOf<ConeCallableSymbol>()
|
val callableSymbols = mutableListOf<ConeCallableSymbol>()
|
||||||
findClass(classId)?.let { javaClass ->
|
for (declaration in firClass.declarations) {
|
||||||
if (firClass.declarations.isEmpty()) {
|
if (declaration is FirNamedFunction) {
|
||||||
for (javaMethod in javaClass.methods) {
|
val methodId = CallableId(callableId.packageName, callableId.className, declaration.name)
|
||||||
val methodName = javaMethod.name
|
if (methodId == callableId) {
|
||||||
val methodId = CallableId(callableId.packageName, callableId.className, methodName)
|
val symbol = declaration.symbol as ConeCallableSymbol
|
||||||
val methodSymbol = FirFunctionSymbol(methodId)
|
callableSymbols += symbol
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -254,14 +70,46 @@ class JavaSymbolProvider(
|
|||||||
FirJavaClass(
|
FirJavaClass(
|
||||||
session, firSymbol as FirClassSymbol, javaClass.name,
|
session, firSymbol as FirClassSymbol, javaClass.name,
|
||||||
javaClass.visibility, javaClass.modality,
|
javaClass.visibility, javaClass.modality,
|
||||||
javaClass.classKind, javaClass.isStatic
|
javaClass.classKind,
|
||||||
|
isTopLevel = classId.relativeClassName.parent().isRoot, isStatic = javaClass.isStatic
|
||||||
).apply {
|
).apply {
|
||||||
for (typeParameter in javaClass.typeParameters) {
|
for (typeParameter in javaClass.typeParameters) {
|
||||||
typeParameters += createTypeParameterSymbol(typeParameter.name).fir
|
typeParameters += createTypeParameterSymbol(session, typeParameter.name).fir
|
||||||
}
|
}
|
||||||
addAnnotationsFrom(javaClass)
|
addAnnotationsFrom(javaClass)
|
||||||
for (supertype in javaClass.supertypes) {
|
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)
|
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.ClassKind
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
import org.jetbrains.kotlin.load.java.structure.JavaClass
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
import org.jetbrains.kotlin.load.java.structure.JavaModifierListOwner
|
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
|
internal val JavaModifierListOwner.modality: Modality
|
||||||
get() = when {
|
get() = when {
|
||||||
@@ -24,3 +47,210 @@ internal val JavaClass.classKind: ClassKind
|
|||||||
isEnum -> ClassKind.ENUM_CLASS
|
isEnum -> ClassKind.ENUM_CLASS
|
||||||
else -> ClassKind.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
|
package org.jetbrains.kotlin.fir.java.declarations
|
||||||
|
|
||||||
import com.intellij.psi.PsiElement
|
|
||||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
import org.jetbrains.kotlin.descriptors.Visibility
|
import org.jetbrains.kotlin.descriptors.Visibility
|
||||||
import org.jetbrains.kotlin.fir.FirSession
|
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.symbols.impl.FirClassSymbol
|
||||||
|
import org.jetbrains.kotlin.fir.types.ConeClassErrorType
|
||||||
|
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
class FirJavaClass(
|
class FirJavaClass(
|
||||||
session: FirSession,
|
session: FirSession,
|
||||||
symbol: FirClassSymbol,
|
override val symbol: FirClassSymbol,
|
||||||
name: Name,
|
name: Name,
|
||||||
visibility: Visibility,
|
visibility: Visibility,
|
||||||
modality: Modality?,
|
modality: Modality?,
|
||||||
classKind: ClassKind,
|
override val classKind: ClassKind,
|
||||||
|
isTopLevel: Boolean,
|
||||||
isStatic: Boolean
|
isStatic: Boolean
|
||||||
) : FirClassImpl(
|
) : FirAbstractMemberDeclaration(
|
||||||
session, psi = null, symbol = symbol, name = name,
|
session, psi = null, name = name,
|
||||||
visibility = visibility, modality = modality,
|
visibility = visibility, modality = modality,
|
||||||
isExpect = false, isActual = false, classKind = classKind, isInner = !isStatic,
|
isExpect = false, isActual = false
|
||||||
isCompanion = false, isData = false, isInline = 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,
|
session, null, symbol, name,
|
||||||
visibility, modality,
|
visibility, modality,
|
||||||
false, isActual = false,
|
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
|
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,
|
isInfix = false, isInline = false, isTailRec = false, isExternal = false, isSuspend = false,
|
||||||
receiverTypeRef = null, returnTypeRef = returnTypeRef
|
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
|
package org.jetbrains.kotlin.fir
|
||||||
|
|
||||||
import org.jetbrains.kotlin.analyzer.ModuleInfo
|
import org.jetbrains.kotlin.analyzer.ModuleInfo
|
||||||
import org.jetbrains.kotlin.fir.resolve.FirProvider
|
import org.jetbrains.kotlin.fir.resolve.*
|
||||||
import org.jetbrains.kotlin.fir.resolve.FirQualifierResolver
|
|
||||||
import org.jetbrains.kotlin.fir.resolve.FirTypeResolver
|
|
||||||
import org.jetbrains.kotlin.fir.resolve.impl.*
|
import org.jetbrains.kotlin.fir.resolve.impl.*
|
||||||
|
|
||||||
abstract class FirModuleBasedSession(override val moduleInfo: ModuleInfo) : FirSessionBase() {
|
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))
|
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.CallableId
|
||||||
import org.jetbrains.kotlin.fir.symbols.ConeCallableSymbol
|
import org.jetbrains.kotlin.fir.symbols.ConeCallableSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeSymbol
|
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.ClassId
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
|
||||||
@@ -38,4 +40,16 @@ abstract class AbstractFirSymbolProvider : FirSymbolProvider {
|
|||||||
calculated.first
|
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) {
|
return when (this) {
|
||||||
is ConeTypeParameterSymbol -> {
|
is ConeTypeParameterSymbol -> {
|
||||||
ConeTypeParameterTypeImpl(this, isNullable)
|
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
|
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.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.FirCompositeScope
|
||||||
import org.jetbrains.kotlin.fir.scopes.impl.FirMemberTypeParameterScope
|
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() {
|
abstract class FirAbstractTreeTransformerWithSuperTypes(reversedScopePriority: Boolean) : FirAbstractTreeTransformer() {
|
||||||
protected val towerScope = FirCompositeScope(mutableListOf(), reversedPriority = reversedScopePriority)
|
protected val towerScope = FirCompositeScope(mutableListOf(), reversedPriority = reversedScopePriority)
|
||||||
@@ -37,74 +23,6 @@ abstract class FirAbstractTreeTransformerWithSuperTypes(reversedScopePriority: B
|
|||||||
return result
|
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() {
|
protected fun FirMemberDeclaration.addTypeParametersScope() {
|
||||||
val scopes = towerScope.scopes
|
val scopes = towerScope.scopes
|
||||||
if (typeParameters.isNotEmpty()) {
|
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.expressions.*
|
||||||
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
|
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
|
||||||
import org.jetbrains.kotlin.fir.references.FirResolvedCallableReferenceImpl
|
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.resolve.toSymbol
|
||||||
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
|
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
|
||||||
import org.jetbrains.kotlin.fir.scopes.ProcessorAction.NEXT
|
import org.jetbrains.kotlin.fir.scopes.ProcessorAction.NEXT
|
||||||
import org.jetbrains.kotlin.fir.scopes.impl.*
|
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.ConeCallableSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterSymbol
|
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||||
@@ -53,7 +56,7 @@ class FirAccessResolveTransformer : FirAbstractTreeTransformerWithSuperTypes(rev
|
|||||||
|
|
||||||
private fun FirRegularClass.buildUseSiteScope(useSiteSession: FirSession = session): FirClassUseSiteScope {
|
private fun FirRegularClass.buildUseSiteScope(useSiteSession: FirSession = session): FirClassUseSiteScope {
|
||||||
val superTypeScope = FirCompositeScope(mutableListOf())
|
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)
|
lookupSuperTypes(this, lookupInterfaces = true, deep = false, useSiteSession = useSiteSession)
|
||||||
.mapNotNullTo(superTypeScope.scopes) { useSiteSuperType ->
|
.mapNotNullTo(superTypeScope.scopes) { useSiteSuperType ->
|
||||||
if (useSiteSuperType is ConeClassErrorType) return@mapNotNullTo null
|
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.render
|
||||||
import org.jetbrains.kotlin.fir.resolve.FirProvider
|
import org.jetbrains.kotlin.fir.resolve.FirProvider
|
||||||
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
|
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.FirPosition
|
||||||
import org.jetbrains.kotlin.fir.scopes.addImportingScopes
|
import org.jetbrains.kotlin.fir.scopes.addImportingScopes
|
||||||
import org.jetbrains.kotlin.fir.scopes.impl.*
|
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.declarations.*
|
||||||
import org.jetbrains.kotlin.fir.resolve.FirProvider
|
import org.jetbrains.kotlin.fir.resolve.FirProvider
|
||||||
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
|
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.FirPosition
|
||||||
import org.jetbrains.kotlin.fir.scopes.addImportingScopes
|
import org.jetbrains.kotlin.fir.scopes.addImportingScopes
|
||||||
import org.jetbrains.kotlin.fir.scopes.impl.*
|
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.resolve.impl.FirDependenciesSymbolProviderImpl
|
||||||
import org.jetbrains.kotlin.fir.scopes.FirScope
|
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)) {
|
val provider = when (val symbolProvider = FirSymbolProvider.getInstance(session)) {
|
||||||
is FirCompositeSymbolProvider -> symbolProvider.takeIf { !lookupInFir }?.providers?.find {
|
is FirCompositeSymbolProvider -> symbolProvider.takeIf { !lookupInFir }?.providers?.find {
|
||||||
it is FirDependenciesSymbolProviderImpl
|
it is FirDependenciesSymbolProviderImpl
|
||||||
|
|||||||
@@ -56,6 +56,10 @@ class FirRenderer(builder: StringBuilder) : FirVisitorVoid() {
|
|||||||
printer.popIndent()
|
printer.popIndent()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun newLine() {
|
||||||
|
println()
|
||||||
|
}
|
||||||
|
|
||||||
override fun visitElement(element: FirElement) {
|
override fun visitElement(element: FirElement) {
|
||||||
element.acceptChildren(this)
|
element.acceptChildren(this)
|
||||||
}
|
}
|
||||||
@@ -214,22 +218,32 @@ class FirRenderer(builder: StringBuilder) : FirVisitorVoid() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun FirDeclarationContainer.renderDeclarations() {
|
private fun FirDeclarationContainer.renderDeclarations() {
|
||||||
|
renderInBraces {
|
||||||
|
for (declaration in declarations) {
|
||||||
|
declaration.accept(this@FirRenderer)
|
||||||
|
println()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun renderInBraces(f: () -> Unit) {
|
||||||
println(" {")
|
println(" {")
|
||||||
pushIndent()
|
pushIndent()
|
||||||
for (declaration in declarations) {
|
f()
|
||||||
declaration.accept(this@FirRenderer)
|
|
||||||
println()
|
|
||||||
}
|
|
||||||
popIndent()
|
popIndent()
|
||||||
println("}")
|
println("}")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitRegularClass(regularClass: FirRegularClass) {
|
fun renderSupertypes(regularClass: FirRegularClass) {
|
||||||
visitMemberDeclaration(regularClass)
|
|
||||||
if (regularClass.superTypeRefs.isNotEmpty()) {
|
if (regularClass.superTypeRefs.isNotEmpty()) {
|
||||||
print(" : ")
|
print(" : ")
|
||||||
regularClass.superTypeRefs.renderSeparated()
|
regularClass.superTypeRefs.renderSeparated()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitRegularClass(regularClass: FirRegularClass) {
|
||||||
|
visitMemberDeclaration(regularClass)
|
||||||
|
renderSupertypes(regularClass)
|
||||||
regularClass.renderDeclarations()
|
regularClass.renderDeclarations()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -345,14 +359,12 @@ class FirRenderer(builder: StringBuilder) : FirVisitorVoid() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visitBlock(block: FirBlock) {
|
override fun visitBlock(block: FirBlock) {
|
||||||
println(" {")
|
renderInBraces {
|
||||||
pushIndent()
|
for (statement in block.statements) {
|
||||||
for (statement in block.statements) {
|
statement.accept(this)
|
||||||
statement.accept(this)
|
println()
|
||||||
println()
|
}
|
||||||
}
|
}
|
||||||
popIndent()
|
|
||||||
println("}")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitTypeAlias(typeAlias: FirTypeAlias) {
|
override fun visitTypeAlias(typeAlias: FirTypeAlias) {
|
||||||
@@ -657,8 +669,10 @@ class FirRenderer(builder: StringBuilder) : FirVisitorVoid() {
|
|||||||
buildString {
|
buildString {
|
||||||
append("ft<")
|
append("ft<")
|
||||||
append(lowerBound.asString())
|
append(lowerBound.asString())
|
||||||
|
append(lowerBound.nullability.suffix)
|
||||||
append(", ")
|
append(", ")
|
||||||
append(upperBound.asString())
|
append(upperBound.asString())
|
||||||
|
append(upperBound.nullability.suffix)
|
||||||
append(">")
|
append(">")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
package org.jetbrains.kotlin.fir
|
package org.jetbrains.kotlin.fir
|
||||||
|
|
||||||
import org.jetbrains.kotlin.analyzer.ModuleInfo
|
import org.jetbrains.kotlin.analyzer.ModuleInfo
|
||||||
|
import org.jetbrains.kotlin.utils.Jsr305State
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
interface FirSession {
|
interface FirSession {
|
||||||
@@ -13,6 +14,8 @@ interface FirSession {
|
|||||||
|
|
||||||
val sessionProvider: FirSessionProvider? get() = null
|
val sessionProvider: FirSessionProvider? get() = null
|
||||||
|
|
||||||
|
val jsr305State: Jsr305State? get() = null
|
||||||
|
|
||||||
val components: Map<KClass<*>, Any>
|
val components: Map<KClass<*>, Any>
|
||||||
|
|
||||||
fun <T : Any> getService(kclass: KClass<T>): T =
|
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 {
|
fun <T : FirElement, D> T.transformSingle(transformer: FirTransformer<D>, data: D): T {
|
||||||
return this.transform<T, D>(transformer, data).single
|
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.descriptors.annotations.AnnotationUseSiteTarget
|
||||||
import org.jetbrains.kotlin.fir.BaseTransformedType
|
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.types.FirTypeRef
|
||||||
import org.jetbrains.kotlin.fir.visitors.FirVisitor
|
import org.jetbrains.kotlin.fir.visitors.FirVisitor
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
|
||||||
@BaseTransformedType
|
@BaseTransformedType
|
||||||
interface FirAnnotationCall : FirCall {
|
interface FirAnnotationCall : FirCall {
|
||||||
@@ -24,4 +27,7 @@ interface FirAnnotationCall : FirCall {
|
|||||||
annotationTypeRef.accept(visitor, data)
|
annotationTypeRef.accept(visitor, data)
|
||||||
super.acceptChildren(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
|
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
|
import org.jetbrains.kotlin.fir.visitors.FirVisitor
|
||||||
|
|
||||||
interface FirExpression : FirStatement {
|
interface FirExpression : FirStatement {
|
||||||
override fun <R, D> accept(visitor: FirVisitor<R, D>, data: D): R =
|
override fun <R, D> accept(visitor: FirVisitor<R, D>, data: D): R =
|
||||||
visitor.visitExpression(this, data)
|
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>()
|
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 {
|
fun isMutable(type: KotlinType): Boolean {
|
||||||
val classDescriptor = TypeUtils.getClassDescriptor(type)
|
val classDescriptor = TypeUtils.getClassDescriptor(type)
|
||||||
return classDescriptor != null && isMutable(classDescriptor)
|
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 {
|
fun isReadOnly(type: KotlinType): Boolean {
|
||||||
val classDescriptor = TypeUtils.getClassDescriptor(type)
|
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.ReportLevel
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
|
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
|
||||||
|
|
||||||
private val TYPE_QUALIFIER_NICKNAME_FQNAME = FqName("javax.annotation.meta.TypeQualifierNickname")
|
val TYPE_QUALIFIER_NICKNAME_FQNAME = FqName("javax.annotation.meta.TypeQualifierNickname")
|
||||||
private val TYPE_QUALIFIER_FQNAME = FqName("javax.annotation.meta.TypeQualifier")
|
val TYPE_QUALIFIER_FQNAME = FqName("javax.annotation.meta.TypeQualifier")
|
||||||
private val TYPE_QUALIFIER_DEFAULT_FQNAME = FqName("javax.annotation.meta.TypeQualifierDefault")
|
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
|
FqName("javax.annotation.ParametersAreNullableByDefault") to
|
||||||
NullabilityQualifierWithApplicability(
|
NullabilityQualifierWithApplicability(
|
||||||
NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NULLABLE),
|
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? {
|
operator fun get(applicabilityType: AnnotationTypeQualifierResolver.QualifierApplicabilityType?): JavaTypeQualifiers? {
|
||||||
val nullabilityQualifierWithMigrationStatus = nullabilityQualifiers[applicabilityType] ?: return null
|
val nullabilityQualifierWithMigrationStatus = nullabilityQualifiers[applicabilityType] ?: return null
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -462,7 +462,7 @@ class SignatureEnhancement(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createJavaTypeQualifiers(
|
fun createJavaTypeQualifiers(
|
||||||
nullability: NullabilityQualifier?,
|
nullability: NullabilityQualifier?,
|
||||||
mutability: MutabilityQualifier?,
|
mutability: MutabilityQualifier?,
|
||||||
forWarning: Boolean,
|
forWarning: Boolean,
|
||||||
@@ -474,7 +474,7 @@ private fun createJavaTypeQualifiers(
|
|||||||
return JavaTypeQualifiers(nullability, mutability, true, forWarning)
|
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) {
|
if (isCovariant) {
|
||||||
val supertypeQualifier = if (low in this) low else if (high in this) high else null
|
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
|
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()
|
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)
|
if (own == NullabilityQualifier.FORCE_FLEXIBILITY)
|
||||||
NullabilityQualifier.FORCE_FLEXIBILITY
|
NullabilityQualifier.FORCE_FLEXIBILITY
|
||||||
else
|
else
|
||||||
|
|||||||
+2
-2
@@ -45,7 +45,7 @@ fun KotlinType.enhance(qualifiers: (Int) -> JavaTypeQualifiers) = unwrap().enhan
|
|||||||
fun KotlinType.hasEnhancedNullability()
|
fun KotlinType.hasEnhancedNullability()
|
||||||
= annotations.findAnnotation(JvmAnnotationNames.ENHANCED_NULLABILITY_ANNOTATION) != null
|
= annotations.findAnnotation(JvmAnnotationNames.ENHANCED_NULLABILITY_ANNOTATION) != null
|
||||||
|
|
||||||
private enum class TypeComponentPosition {
|
enum class TypeComponentPosition {
|
||||||
FLEXIBLE_LOWER,
|
FLEXIBLE_LOWER,
|
||||||
FLEXIBLE_UPPER,
|
FLEXIBLE_UPPER,
|
||||||
INFLEXIBLE
|
INFLEXIBLE
|
||||||
@@ -147,7 +147,7 @@ private fun List<Annotations>.compositeAnnotationsOrSingle() = when (size) {
|
|||||||
else -> CompositeAnnotations(this.toList())
|
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 data class EnhancementResult<out T>(val result: T, val enhancementAnnotations: Annotations?)
|
||||||
private fun <T> T.noChange() = EnhancementResult(this, null)
|
private fun <T> T.noChange() = EnhancementResult(this, null)
|
||||||
|
|||||||
+5
-5
@@ -27,11 +27,11 @@ enum class MutabilityQualifier {
|
|||||||
MUTABLE
|
MUTABLE
|
||||||
}
|
}
|
||||||
|
|
||||||
class JavaTypeQualifiers internal constructor(
|
class JavaTypeQualifiers(
|
||||||
val nullability: NullabilityQualifier?,
|
val nullability: NullabilityQualifier?,
|
||||||
val mutability: MutabilityQualifier?,
|
val mutability: MutabilityQualifier?,
|
||||||
internal val isNotNullTypeParameter: Boolean,
|
val isNotNullTypeParameter: Boolean,
|
||||||
internal val isNullabilityQualifierForWarning: Boolean = false
|
val isNullabilityQualifierForWarning: Boolean = false
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
val NONE = JavaTypeQualifiers(null, null, false)
|
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 constructor(): super<R|A<Some>|>()
|
||||||
|
|
||||||
public final function test(): R|kotlin/Unit| {
|
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 com.intellij.psi.search.FileTypeIndex
|
||||||
import org.jetbrains.kotlin.fir.FirRenderer
|
import org.jetbrains.kotlin.fir.FirRenderer
|
||||||
import org.jetbrains.kotlin.fir.builder.RawFirBuilder
|
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.declarations.FirFile
|
||||||
import org.jetbrains.kotlin.fir.dependenciesWithoutSelf
|
import org.jetbrains.kotlin.fir.dependenciesWithoutSelf
|
||||||
import org.jetbrains.kotlin.fir.java.FirJavaModuleBasedSession
|
import org.jetbrains.kotlin.fir.java.FirJavaModuleBasedSession
|
||||||
import org.jetbrains.kotlin.fir.java.FirLibrarySession
|
import org.jetbrains.kotlin.fir.java.FirLibrarySession
|
||||||
import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider
|
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.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.impl.FirProviderImpl
|
||||||
import org.jetbrains.kotlin.fir.resolve.transformers.FirTotalResolveTransformer
|
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.service
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
|
||||||
import org.jetbrains.kotlin.idea.KotlinFileType
|
import org.jetbrains.kotlin.idea.KotlinFileType
|
||||||
import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo
|
import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo
|
||||||
import org.jetbrains.kotlin.idea.caches.project.isLibraryClasses
|
import org.jetbrains.kotlin.idea.caches.project.isLibraryClasses
|
||||||
@@ -64,9 +75,11 @@ abstract class AbstractFirMultiModuleResolveTest : AbstractMultiModuleTest() {
|
|||||||
|
|
||||||
private fun doFirResolveTest(dirPath: String) {
|
private fun doFirResolveTest(dirPath: String) {
|
||||||
val firFiles = mutableListOf<FirFile>()
|
val firFiles = mutableListOf<FirFile>()
|
||||||
|
val sessions = mutableListOf<FirJavaModuleBasedSession>()
|
||||||
val provider = FirProjectSessionProvider(project)
|
val provider = FirProjectSessionProvider(project)
|
||||||
for (module in project.allModules().drop(1)) {
|
for (module in project.allModules().drop(1)) {
|
||||||
val session = createSession(module, provider)
|
val session = createSession(module, provider)
|
||||||
|
sessions += session
|
||||||
|
|
||||||
val builder = RawFirBuilder(session, stubMode = false)
|
val builder = RawFirBuilder(session, stubMode = false)
|
||||||
val psiManager = PsiManager.getInstance(project)
|
val psiManager = PsiManager.getInstance(project)
|
||||||
@@ -112,5 +125,54 @@ abstract class AbstractFirMultiModuleResolveTest : AbstractMultiModuleTest() {
|
|||||||
val expectedPath = expectedTxtPath((file.psi as PsiFile).virtualFile)
|
val expectedPath = expectedTxtPath((file.psi as PsiFile).virtualFile)
|
||||||
KotlinTestUtils.assertEqualsToFile(File(expectedPath), firFileDump)
|
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/");
|
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")
|
@TestMetadata("basicWithJava")
|
||||||
public void testBasicWithJava() throws Exception {
|
public void testBasicWithJava() throws Exception {
|
||||||
runTest("idea/testData/fir/multiModule/basicWithJava/");
|
runTest("idea/testData/fir/multiModule/basicWithJava/");
|
||||||
@@ -44,6 +54,11 @@ public class FirMultiModuleResolveTestGenerated extends AbstractFirMultiModuleRe
|
|||||||
runTest("idea/testData/fir/multiModule/basicWithJavaFakeOverride/");
|
runTest("idea/testData/fir/multiModule/basicWithJavaFakeOverride/");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("basicWithPrimitiveJava")
|
||||||
|
public void testBasicWithPrimitiveJava() throws Exception {
|
||||||
|
runTest("idea/testData/fir/multiModule/basicWithPrimitiveJava/");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("mppFakeOverrides")
|
@TestMetadata("mppFakeOverrides")
|
||||||
public void testMppFakeOverrides() throws Exception {
|
public void testMppFakeOverrides() throws Exception {
|
||||||
runTest("idea/testData/fir/multiModule/mppFakeOverrides/");
|
runTest("idea/testData/fir/multiModule/mppFakeOverrides/");
|
||||||
|
|||||||
Reference in New Issue
Block a user