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:
Mikhail Glukhikh
2019-02-15 10:36:57 +03:00
parent 060bd1b464
commit f31faafd72
56 changed files with 2042 additions and 336 deletions
@@ -65,6 +65,10 @@ sealed class ConeKotlinType : ConeKotlinTypeProjection(), ConeTypedProjection, K
abstract val nullability: ConeNullability
}
val ConeKotlinType.isNullable: Boolean get() = nullability != ConeNullability.NOT_NULL
val ConeKotlinType.isMarkedNullable: Boolean get() = nullability == ConeNullability.NULLABLE
class ConeKotlinErrorType(val reason: String) : ConeKotlinType() {
override val typeArguments: Array<out ConeKotlinTypeProjection>
get() = EMPTY_ARRAY
@@ -9,11 +9,11 @@ import com.intellij.openapi.project.Project
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.java.scopes.JavaFirScopeProvider
import org.jetbrains.kotlin.fir.resolve.FirProvider
import org.jetbrains.kotlin.fir.resolve.FirScopeProvider
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
import org.jetbrains.kotlin.fir.resolve.impl.FirCompositeSymbolProvider
import org.jetbrains.kotlin.fir.resolve.impl.FirDependenciesSymbolProviderImpl
import org.jetbrains.kotlin.fir.resolve.impl.FirLibrarySymbolProviderImpl
import org.jetbrains.kotlin.fir.resolve.impl.*
class FirJavaModuleBasedSession(
moduleInfo: ModuleInfo,
@@ -21,7 +21,6 @@ class FirJavaModuleBasedSession(
scope: GlobalSearchScope,
dependenciesProvider: FirSymbolProvider? = null
) : FirModuleBasedSession(moduleInfo) {
init {
sessionProvider.sessionCache[moduleInfo] = this
registerComponent(
@@ -35,6 +34,15 @@ class FirJavaModuleBasedSession(
)
)
)
registerComponent(
FirScopeProvider::class,
FirCompositeScopeProvider(
listOf(
JavaFirScopeProvider(),
FirRegularScopeProvider()
)
)
)
}
}
@@ -55,6 +63,15 @@ class FirLibrarySession(
)
)
)
registerComponent(
FirScopeProvider::class,
FirCompositeScopeProvider(
listOf(
JavaFirScopeProvider(),
FirRegularScopeProvider()
)
)
)
}
}
@@ -9,37 +9,23 @@ import com.intellij.openapi.project.Project
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirNamedFunction
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.impl.FirModifiableClass
import org.jetbrains.kotlin.fir.declarations.impl.FirTypeParameterImpl
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
import org.jetbrains.kotlin.fir.expressions.FirArrayOfCall
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.impl.*
import org.jetbrains.kotlin.fir.java.declarations.FirJavaClass
import org.jetbrains.kotlin.fir.java.declarations.FirJavaMethod
import org.jetbrains.kotlin.fir.java.declarations.FirJavaValueParameter
import org.jetbrains.kotlin.fir.java.types.FirJavaTypeRef
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
import org.jetbrains.kotlin.fir.references.FirResolvedCallableReferenceImpl
import org.jetbrains.kotlin.fir.resolve.AbstractFirSymbolProvider
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
import org.jetbrains.kotlin.fir.service
import org.jetbrains.kotlin.fir.symbols.*
import org.jetbrains.kotlin.fir.symbols.CallableId
import org.jetbrains.kotlin.fir.symbols.ConeCallableSymbol
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.impl.ConeClassTypeImpl
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
import org.jetbrains.kotlin.fir.types.impl.FirResolvedTypeRefImpl
import org.jetbrains.kotlin.ir.expressions.IrConstKind
import org.jetbrains.kotlin.load.java.JavaClassFinder
import org.jetbrains.kotlin.load.java.structure.*
import org.jetbrains.kotlin.load.java.structure.JavaClass
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.jvm.KotlinJavaPsiFacade
import org.jetbrains.kotlin.types.Variance
class JavaSymbolProvider(
val session: FirSession,
@@ -49,149 +35,6 @@ class JavaSymbolProvider(
private val facade: KotlinJavaPsiFacade get() = KotlinJavaPsiFacade.getInstance(project)
private fun JavaAnnotation.toFirAnnotationCall(): FirAnnotationCall {
return FirAnnotationCallImpl(
session, psi = null, useSiteTarget = null,
annotationTypeRef = FirResolvedTypeRefImpl(
session = session,
psi = null,
type = ConeClassTypeImpl(FirClassSymbol(classId!!).toLookupTag(), emptyArray(), isNullable = false),
isMarkedNullable = true,
annotations = emptyList()
)
).apply {
for (argument in this@toFirAnnotationCall.arguments) {
arguments += argument.toFirExpression()
}
}
}
// TODO: use kind here
private fun <T> List<T>.createArrayOfCall(@Suppress("UNUSED_PARAMETER") kind: IrConstKind<T>): FirArrayOfCall {
return FirArrayOfCallImpl(session, null).apply {
for (element in this@createArrayOfCall) {
arguments += element.createConstant()
}
}
}
private fun Any?.createConstant(): FirExpression {
return when (this) {
is Byte -> FirConstExpressionImpl(session, null, IrConstKind.Byte, this)
is Short -> FirConstExpressionImpl(session, null, IrConstKind.Short, this)
is Int -> FirConstExpressionImpl(session, null, IrConstKind.Int, this)
is Long -> FirConstExpressionImpl(session, null, IrConstKind.Long, this)
is Char -> FirConstExpressionImpl(session, null, IrConstKind.Char, this)
is Float -> FirConstExpressionImpl(session, null, IrConstKind.Float, this)
is Double -> FirConstExpressionImpl(session, null, IrConstKind.Double, this)
is Boolean -> FirConstExpressionImpl(session, null, IrConstKind.Boolean, this)
is String -> FirConstExpressionImpl(session, null, IrConstKind.String, this)
null -> FirConstExpressionImpl(session, null, IrConstKind.Null, null)
else -> FirErrorExpressionImpl(session, null, "Unknown value in JavaLiteralAnnotationArgument: $this")
}
}
private fun JavaAnnotationArgument.toFirExpression(): FirExpression {
// TODO: this.name
return when (this) {
is JavaLiteralAnnotationArgument -> {
when (val value = value) {
is ByteArray -> value.toList().createArrayOfCall(IrConstKind.Byte)
is ShortArray -> value.toList().createArrayOfCall(IrConstKind.Short)
is IntArray -> value.toList().createArrayOfCall(IrConstKind.Int)
is LongArray -> value.toList().createArrayOfCall(IrConstKind.Long)
is CharArray -> value.toList().createArrayOfCall(IrConstKind.Char)
is FloatArray -> value.toList().createArrayOfCall(IrConstKind.Float)
is DoubleArray -> value.toList().createArrayOfCall(IrConstKind.Double)
is BooleanArray -> value.toList().createArrayOfCall(IrConstKind.Boolean)
else -> value.createConstant()
}
}
is JavaArrayAnnotationArgument -> FirArrayOfCallImpl(session, null).apply {
for (element in getElements()) {
arguments += element.toFirExpression()
}
}
is JavaEnumValueAnnotationArgument -> {
FirFunctionCallImpl(session, null).apply {
val classId = this@toFirExpression.enumClassId
val entryName = this@toFirExpression.entryName
val calleeReference = if (classId != null && entryName != null) {
val callableSymbol = session.service<FirSymbolProvider>().getCallableSymbols(
CallableId(classId.packageFqName, classId.relativeClassName, entryName)
).firstOrNull()
callableSymbol?.let {
FirResolvedCallableReferenceImpl(session, null, entryName, it)
}
} else {
null
}
this.calleeReference = calleeReference
?: FirErrorNamedReference(session, null, "Strange Java enum value: ${this@toFirExpression}")
}
}
is JavaClassObjectAnnotationArgument -> FirGetClassCallImpl(session, null).apply {
val referencedType = getReferencedType()
arguments += FirClassReferenceExpressionImpl(session, null, referencedType.toFirResolvedTypeRef())
}
is JavaAnnotationAsAnnotationArgument -> getAnnotation().toFirAnnotationCall()
else -> FirErrorExpressionImpl(session, null, "Unknown JavaAnnotationArgument: ${this::class.java}")
}
}
private fun JavaClassifierType.toFirResolvedTypeRef(): FirResolvedTypeRef {
val coneType = when (val classifier = classifier) {
is JavaClass -> {
val lookupTag = ConeClassLikeLookupTagImpl(classifier.classId!!)
ConeClassTypeImpl(lookupTag, typeArguments.map { it.toConeProjection() }.toTypedArray(), isNullable = false)
}
is JavaTypeParameter -> {
// TODO: it's unclear how to identify type parameter by the symbol
// TODO: some type parameter cache (provider?)
val symbol = createTypeParameterSymbol(classifier.name)
ConeTypeParameterTypeImpl(symbol, isNullable = false)
}
else -> ConeClassErrorType(reason = "Unexpected classifier: $classifier")
}
return FirResolvedTypeRefImpl(
session, psi = null, type = coneType,
isMarkedNullable = false, annotations = annotations.map { it.toFirAnnotationCall() }
)
}
private fun JavaType.toFirJavaTypeRef(): FirJavaTypeRef {
val annotations = (this as? JavaClassifierType)?.annotations.orEmpty()
return FirJavaTypeRef(session, annotations = annotations.map { it.toFirAnnotationCall() }, type = this)
}
private fun JavaType.toFirResolvedTypeRef(): FirResolvedTypeRef {
if (this is JavaClassifierType) return toFirResolvedTypeRef()
return FirResolvedTypeRefImpl(
session, psi = null, type = ConeClassErrorType("Unexpected JavaType: $this"),
isMarkedNullable = false, annotations = emptyList()
)
}
private fun JavaType.toConeProjection(): ConeKotlinTypeProjection {
if (this is JavaClassifierType) {
return toFirResolvedTypeRef().type
}
return ConeClassErrorType("Unexpected type argument: $this")
}
private fun createTypeParameterSymbol(name: Name): FirTypeParameterSymbol {
val firSymbol = FirTypeParameterSymbol()
FirTypeParameterImpl(session, null, firSymbol, name, variance = Variance.INVARIANT, isReified = false)
return firSymbol
}
private fun FirAbstractAnnotatedElement.addAnnotationsFrom(javaAnnotationOwner: JavaAnnotationOwner) {
for (annotation in javaAnnotationOwner.annotations) {
annotations += annotation.toFirAnnotationCall()
}
}
private fun findClass(classId: ClassId): JavaClass? = facade.findClass(JavaClassFinder.Request(classId), searchScope)
override fun getCallableSymbols(callableId: CallableId): List<ConeCallableSymbol> {
@@ -201,39 +44,12 @@ class JavaSymbolProvider(
?: return@lookupCacheOrCalculate emptyList()
val firClass = classSymbol.fir as FirModifiableClass
val callableSymbols = mutableListOf<ConeCallableSymbol>()
findClass(classId)?.let { javaClass ->
if (firClass.declarations.isEmpty()) {
for (javaMethod in javaClass.methods) {
val methodName = javaMethod.name
val methodId = CallableId(callableId.packageName, callableId.className, methodName)
val methodSymbol = FirFunctionSymbol(methodId)
val memberFunction = FirJavaMethod(
session, methodSymbol, methodName,
javaMethod.visibility, javaMethod.modality,
returnTypeRef = javaMethod.returnType.toFirJavaTypeRef()
).apply {
for (typeParameter in javaMethod.typeParameters) {
typeParameters += createTypeParameterSymbol(typeParameter.name).fir
}
addAnnotationsFrom(javaMethod)
for (valueParameter in javaMethod.valueParameters) {
valueParameters += FirJavaValueParameter(
session, valueParameter.name ?: Name.special("<anonymous Java parameter>"),
returnTypeRef = valueParameter.type.toFirJavaTypeRef(),
isVararg = valueParameter.isVararg
)
}
}
firClass.declarations += memberFunction
}
}
for (declaration in firClass.declarations) {
if (declaration is FirNamedFunction) {
val methodId = CallableId(callableId.packageName, callableId.className, declaration.name)
if (methodId == callableId) {
val symbol = declaration.symbol as ConeCallableSymbol
callableSymbols += symbol
}
for (declaration in firClass.declarations) {
if (declaration is FirNamedFunction) {
val methodId = CallableId(callableId.packageName, callableId.className, declaration.name)
if (methodId == callableId) {
val symbol = declaration.symbol as ConeCallableSymbol
callableSymbols += symbol
}
}
}
@@ -254,14 +70,46 @@ class JavaSymbolProvider(
FirJavaClass(
session, firSymbol as FirClassSymbol, javaClass.name,
javaClass.visibility, javaClass.modality,
javaClass.classKind, javaClass.isStatic
javaClass.classKind,
isTopLevel = classId.relativeClassName.parent().isRoot, isStatic = javaClass.isStatic
).apply {
for (typeParameter in javaClass.typeParameters) {
typeParameters += createTypeParameterSymbol(typeParameter.name).fir
typeParameters += createTypeParameterSymbol(session, typeParameter.name).fir
}
addAnnotationsFrom(javaClass)
for (supertype in javaClass.supertypes) {
superTypeRefs += supertype.toFirResolvedTypeRef()
superTypeRefs += supertype.toFirResolvedTypeRef(session)
}
// TODO: fields
// TODO: may be we can process methods later.
// However, they should be built up to override resolve stage
for (javaMethod in javaClass.methods) {
if (javaMethod.isStatic) continue // TODO: statics
val methodName = javaMethod.name
val methodId = CallableId(classId.packageFqName, classId.relativeClassName, methodName)
val methodSymbol = FirFunctionSymbol(methodId)
val returnType = javaMethod.returnType
val firJavaMethod = FirJavaMethod(
session, methodSymbol, methodName,
javaMethod.visibility, javaMethod.modality,
returnTypeRef = returnType.toFirJavaTypeRef(session)
).apply {
for (typeParameter in javaMethod.typeParameters) {
typeParameters += createTypeParameterSymbol(session, typeParameter.name).fir
}
addAnnotationsFrom(javaMethod)
for (valueParameter in javaMethod.valueParameters) {
val parameterType = valueParameter.type
valueParameters += FirJavaValueParameter(
session, valueParameter.name ?: Name.special("<anonymous Java parameter>"),
returnTypeRef = parameterType.toFirJavaTypeRef(session),
isVararg = valueParameter.isVararg
).apply {
addAnnotationsFrom(valueParameter)
}
}
}
declarations += firJavaMethod
}
}
}
@@ -275,5 +123,12 @@ class JavaSymbolProvider(
FqName(javaPackage.qualifiedName)
}
}
fun getJavaTopLevelClasses(): List<FirRegularClass> {
return classCache.values
.filterIsInstance<FirClassSymbol>()
.filter { it.classId.relativeClassName.parent().isRoot }
.map { it.fir }
}
}
@@ -7,8 +7,31 @@ package org.jetbrains.kotlin.fir.java
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.load.java.structure.JavaClass
import org.jetbrains.kotlin.load.java.structure.JavaModifierListOwner
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.impl.FirTypeParameterImpl
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
import org.jetbrains.kotlin.fir.expressions.FirArrayOfCall
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.impl.*
import org.jetbrains.kotlin.fir.java.types.FirJavaTypeRef
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
import org.jetbrains.kotlin.fir.references.FirResolvedCallableReferenceImpl
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
import org.jetbrains.kotlin.fir.service
import org.jetbrains.kotlin.fir.symbols.CallableId
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTagImpl
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.impl.ConeClassTypeImpl
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
import org.jetbrains.kotlin.fir.types.impl.FirResolvedTypeRefImpl
import org.jetbrains.kotlin.ir.expressions.IrConstKind
import org.jetbrains.kotlin.load.java.structure.*
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.Variance
internal val JavaModifierListOwner.modality: Modality
get() = when {
@@ -24,3 +47,210 @@ internal val JavaClass.classKind: ClassKind
isEnum -> ClassKind.ENUM_CLASS
else -> ClassKind.CLASS
}
internal fun ClassId.toConeKotlinType(
typeArguments: Array<ConeKotlinTypeProjection>,
isNullable: Boolean
): ConeLookupTagBasedType {
val lookupTag = ConeClassLikeLookupTagImpl(this)
return ConeClassTypeImpl(lookupTag, typeArguments, isNullable)
}
internal fun FirTypeRef.toNotNullConeKotlinType(): ConeKotlinType =
when (this) {
is FirResolvedTypeRef -> type
is FirJavaTypeRef -> {
val javaType = type
javaType.toNotNullConeKotlinType(session)
}
else -> ConeKotlinErrorType("Unexpected type reference in JavaClassUseSiteScope: ${this::class.java}")
}
internal fun JavaType.toNotNullConeKotlinType(session: FirSession): ConeLookupTagBasedType {
return toConeKotlinTypeWithNullability(session, isNullable = false)
}
internal fun JavaType.toFirJavaTypeRef(session: FirSession): FirJavaTypeRef {
val annotations = (this as? JavaClassifierType)?.annotations.orEmpty()
return FirJavaTypeRef(session, annotations = annotations.map { it.toFirAnnotationCall(session) }, type = this)
}
internal fun JavaClassifierType.toFirResolvedTypeRef(session: FirSession): FirResolvedTypeRef {
val coneType = this.toConeKotlinTypeWithNullability(session, isNullable = false)
return FirResolvedTypeRefImpl(
session, psi = null, type = coneType,
isMarkedNullable = false, annotations = annotations.map { it.toFirAnnotationCall(session) }
)
}
internal fun JavaType.toConeKotlinTypeWithNullability(session: FirSession, isNullable: Boolean): ConeLookupTagBasedType {
return when (this) {
is JavaClassifierType -> {
toConeKotlinTypeWithNullability(session, isNullable)
}
is JavaPrimitiveType -> {
val primitiveType = type
val kotlinPrimitiveName = when (val javaName = primitiveType?.typeName?.asString()) {
null -> "Unit"
else -> javaName.capitalize()
}
val classId = ClassId(FqName("kotlin"), FqName(kotlinPrimitiveName), false)
classId.toConeKotlinType(emptyArray(), isNullable)
}
is JavaArrayType -> {
val componentType = componentType
if (componentType !is JavaPrimitiveType) {
val classId = ClassId(FqName("kotlin"), FqName("Array"), false)
val argumentType = ConeFlexibleType(
componentType.toConeKotlinTypeWithNullability(session, isNullable = false),
componentType.toConeKotlinTypeWithNullability(session, isNullable = true)
)
classId.toConeKotlinType(arrayOf(argumentType), isNullable)
} else {
val javaComponentName = componentType.type?.typeName?.asString()?.capitalize() ?: error("Array of voids")
val classId = ClassId(FqName("kotlin"), FqName(javaComponentName + "Array"), false)
classId.toConeKotlinType(emptyArray(), isNullable)
}
}
is JavaWildcardType -> bound?.toNotNullConeKotlinType(session) ?: run {
val classId = ClassId(FqName("kotlin"), FqName("Any"), false)
classId.toConeKotlinType(emptyArray(), isNullable)
}
else -> error("Strange JavaType: ${this::class.java}")
}
}
internal fun JavaClassifierType.toConeKotlinTypeWithNullability(session: FirSession, isNullable: Boolean): ConeLookupTagBasedType {
return when (val classifier = classifier) {
is JavaClass -> {
classifier.classId!!.toConeKotlinType(typeArguments.map { it.toConeProjection(session) }.toTypedArray(), isNullable)
}
is JavaTypeParameter -> {
// TODO: it's unclear how to identify type parameter by the symbol
// TODO: some type parameter cache (provider?)
val symbol = createTypeParameterSymbol(session, classifier.name)
ConeTypeParameterTypeImpl(symbol, isNullable)
}
else -> ConeClassErrorType(reason = "Unexpected classifier: $classifier")
}
}
internal fun createTypeParameterSymbol(session: FirSession, name: Name): FirTypeParameterSymbol {
val firSymbol = FirTypeParameterSymbol()
FirTypeParameterImpl(session, null, firSymbol, name, variance = Variance.INVARIANT, isReified = false)
return firSymbol
}
internal fun JavaAnnotation.toFirAnnotationCall(session: FirSession): FirAnnotationCall {
return FirAnnotationCallImpl(
session, psi = null, useSiteTarget = null,
annotationTypeRef = FirResolvedTypeRefImpl(
session = session,
psi = null,
type = ConeClassTypeImpl(FirClassSymbol(classId!!).toLookupTag(), emptyArray(), isNullable = false),
isMarkedNullable = true,
annotations = emptyList()
)
).apply {
for (argument in this@toFirAnnotationCall.arguments) {
arguments += argument.toFirExpression(session)
}
}
}
internal fun FirAbstractAnnotatedElement.addAnnotationsFrom(javaAnnotationOwner: JavaAnnotationOwner) {
for (annotation in javaAnnotationOwner.annotations) {
annotations += annotation.toFirAnnotationCall(session)
}
}
private fun JavaType.toConeProjection(session: FirSession): ConeKotlinTypeProjection {
if (this is JavaClassifierType) {
return toConeKotlinTypeWithNullability(session, isNullable = false)
}
return ConeClassErrorType("Unexpected type argument: $this")
}
private fun JavaAnnotationArgument.toFirExpression(session: FirSession): FirExpression {
// TODO: this.name
return when (this) {
is JavaLiteralAnnotationArgument -> {
when (val value = value) {
is ByteArray -> value.toList().createArrayOfCall(session, IrConstKind.Byte)
is ShortArray -> value.toList().createArrayOfCall(session, IrConstKind.Short)
is IntArray -> value.toList().createArrayOfCall(session, IrConstKind.Int)
is LongArray -> value.toList().createArrayOfCall(session, IrConstKind.Long)
is CharArray -> value.toList().createArrayOfCall(session, IrConstKind.Char)
is FloatArray -> value.toList().createArrayOfCall(session, IrConstKind.Float)
is DoubleArray -> value.toList().createArrayOfCall(session, IrConstKind.Double)
is BooleanArray -> value.toList().createArrayOfCall(session, IrConstKind.Boolean)
else -> value.createConstant(session)
}
}
is JavaArrayAnnotationArgument -> FirArrayOfCallImpl(session, null).apply {
for (element in getElements()) {
arguments += element.toFirExpression(session)
}
}
is JavaEnumValueAnnotationArgument -> {
FirFunctionCallImpl(session, null).apply {
val classId = this@toFirExpression.enumClassId
val entryName = this@toFirExpression.entryName
val calleeReference = if (classId != null && entryName != null) {
val callableSymbol = session.service<FirSymbolProvider>().getCallableSymbols(
CallableId(classId.packageFqName, classId.relativeClassName, entryName)
).firstOrNull()
callableSymbol?.let {
FirResolvedCallableReferenceImpl(session, null, entryName, it)
}
} else {
null
}
this.calleeReference = calleeReference
?: FirErrorNamedReference(session, null, "Strange Java enum value: ${this@toFirExpression}")
}
}
is JavaClassObjectAnnotationArgument -> FirGetClassCallImpl(session, null).apply {
val referencedType = getReferencedType()
arguments += FirClassReferenceExpressionImpl(session, null, referencedType.toFirResolvedTypeRef(session))
}
is JavaAnnotationAsAnnotationArgument -> getAnnotation().toFirAnnotationCall(session)
else -> FirErrorExpressionImpl(session, null, "Unknown JavaAnnotationArgument: ${this::class.java}")
}
}
// TODO: use kind here
private fun <T> List<T>.createArrayOfCall(session: FirSession, @Suppress("UNUSED_PARAMETER") kind: IrConstKind<T>): FirArrayOfCall {
return FirArrayOfCallImpl(session, null).apply {
for (element in this@createArrayOfCall) {
arguments += element.createConstant(session)
}
}
}
private fun Any?.createConstant(session: FirSession): FirExpression {
return when (this) {
is Byte -> FirConstExpressionImpl(session, null, IrConstKind.Byte, this)
is Short -> FirConstExpressionImpl(session, null, IrConstKind.Short, this)
is Int -> FirConstExpressionImpl(session, null, IrConstKind.Int, this)
is Long -> FirConstExpressionImpl(session, null, IrConstKind.Long, this)
is Char -> FirConstExpressionImpl(session, null, IrConstKind.Char, this)
is Float -> FirConstExpressionImpl(session, null, IrConstKind.Float, this)
is Double -> FirConstExpressionImpl(session, null, IrConstKind.Double, this)
is Boolean -> FirConstExpressionImpl(session, null, IrConstKind.Boolean, this)
is String -> FirConstExpressionImpl(session, null, IrConstKind.String, this)
null -> FirConstExpressionImpl(session, null, IrConstKind.Null, null)
else -> FirErrorExpressionImpl(session, null, "Unknown value in JavaLiteralAnnotationArgument: $this")
}
}
private fun JavaType.toFirResolvedTypeRef(session: FirSession): FirResolvedTypeRef {
if (this is JavaClassifierType) return toFirResolvedTypeRef(session)
return FirResolvedTypeRefImpl(
session, psi = null, type = ConeClassErrorType("Unexpected JavaType: $this"),
isMarkedNullable = false, annotations = emptyList()
)
}
@@ -5,26 +5,72 @@
package org.jetbrains.kotlin.fir.java.declarations
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.impl.FirClassImpl
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.impl.FirAbstractMemberDeclaration
import org.jetbrains.kotlin.fir.declarations.impl.FirModifiableClass
import org.jetbrains.kotlin.fir.java.scopes.JavaClassEnhancementScope
import org.jetbrains.kotlin.fir.java.scopes.JavaClassUseSiteScope
import org.jetbrains.kotlin.fir.resolve.lookupSuperTypes
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.scopes.impl.FirClassDeclaredMemberScope
import org.jetbrains.kotlin.fir.scopes.impl.FirCompositeScope
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
import org.jetbrains.kotlin.fir.types.ConeClassErrorType
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.name.Name
class FirJavaClass(
session: FirSession,
symbol: FirClassSymbol,
override val symbol: FirClassSymbol,
name: Name,
visibility: Visibility,
modality: Modality?,
classKind: ClassKind,
override val classKind: ClassKind,
isTopLevel: Boolean,
isStatic: Boolean
) : FirClassImpl(
session, psi = null, symbol = symbol, name = name,
) : FirAbstractMemberDeclaration(
session, psi = null, name = name,
visibility = visibility, modality = modality,
isExpect = false, isActual = false, classKind = classKind, isInner = !isStatic,
isCompanion = false, isData = false, isInline = false
)
isExpect = false, isActual = false
), FirRegularClass, FirModifiableClass {
init {
symbol.bind(this)
status.isInner = !isTopLevel && !isStatic
status.isCompanion = false
status.isData = false
status.isInline = false
}
override val superTypeRefs = mutableListOf<FirTypeRef>()
val useSiteScope: JavaClassUseSiteScope by lazy { buildUseSiteScope() }
override val declarations = mutableListOf<FirDeclaration>()
private fun FirRegularClass.buildUseSiteScope(useSiteSession: FirSession = session): JavaClassUseSiteScope {
val superTypeEnhancementScope = FirCompositeScope(mutableListOf())
val declaredScope = FirClassDeclaredMemberScope(this, useSiteSession)
lookupSuperTypes(this, lookupInterfaces = true, deep = false, useSiteSession = useSiteSession)
.mapNotNullTo(superTypeEnhancementScope.scopes) { useSiteSuperType ->
if (useSiteSuperType is ConeClassErrorType) return@mapNotNullTo null
val symbol = useSiteSuperType.lookupTag.toSymbol(useSiteSession)
if (symbol is FirClassSymbol) {
JavaClassEnhancementScope(useSiteSession, symbol.fir.buildUseSiteScope(useSiteSession))
} else {
null
}
}
return JavaClassUseSiteScope(this, useSiteSession, superTypeEnhancementScope, declaredScope)
}
override fun replaceSupertypes(newSupertypes: List<FirTypeRef>): FirRegularClass {
superTypeRefs.clear()
superTypeRefs.addAll(newSupertypes)
return this
}
}
@@ -25,7 +25,7 @@ class FirJavaMethod(
session, null, symbol, name,
visibility, modality,
false, isActual = false,
isOverride = false, // TODO: really it's unknown whether Java methods are overrides or not
isOverride = false,
isOperator = true, // All Java methods with name that allows to use it in operator form are considered operators
isInfix = false, isInline = false, isTailRec = false, isExternal = false, isSuspend = false,
receiverTypeRef = null, returnTypeRef = returnTypeRef
@@ -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
)
}
@@ -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 }
@@ -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
}
}
@@ -0,0 +1,259 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.java.scopes
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.impl.FirMemberFunctionImpl
import org.jetbrains.kotlin.fir.declarations.impl.FirValueParameterImpl
import org.jetbrains.kotlin.fir.expressions.FirAnnotationContainer
import org.jetbrains.kotlin.fir.java.declarations.FirJavaMethod
import org.jetbrains.kotlin.fir.java.declarations.FirJavaValueParameter
import org.jetbrains.kotlin.fir.java.enhancement.EnhancementSignatureParts
import org.jetbrains.kotlin.fir.java.enhancement.FirAnnotationTypeQualifierResolver
import org.jetbrains.kotlin.fir.java.enhancement.FirJavaEnhancementContext
import org.jetbrains.kotlin.fir.java.enhancement.copyWithNewDefaultTypeQualifiers
import org.jetbrains.kotlin.fir.java.types.FirJavaTypeRef
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
import org.jetbrains.kotlin.fir.symbols.ConeCallableSymbol
import org.jetbrains.kotlin.fir.symbols.ConeFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.load.java.AnnotationTypeQualifierResolver
import org.jetbrains.kotlin.load.java.structure.JavaPrimitiveType
import org.jetbrains.kotlin.load.java.typeEnhancement.PREDEFINED_FUNCTION_ENHANCEMENT_INFO_BY_SIGNATURE
import org.jetbrains.kotlin.load.java.typeEnhancement.PredefinedFunctionEnhancementInfo
import org.jetbrains.kotlin.load.kotlin.SignatureBuildingComponents
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.Jsr305State
class JavaClassEnhancementScope(
session: FirSession,
private val useSiteScope: JavaClassUseSiteScope
) : FirScope {
private val owner: FirRegularClass get() = useSiteScope.symbol.fir
private val jsr305State: Jsr305State = session.jsr305State ?: Jsr305State.DEFAULT
private val typeQualifierResolver = FirAnnotationTypeQualifierResolver(jsr305State)
private val context: FirJavaEnhancementContext =
FirJavaEnhancementContext(session) { null }
private val enhancements = mutableMapOf<ConeCallableSymbol, ConeCallableSymbol>()
override fun processFunctionsByName(name: Name, processor: (ConeFunctionSymbol) -> ProcessorAction): ProcessorAction {
useSiteScope.processFunctionsByName(name) process@{ original ->
val function = enhancements.getOrPut(original) { enhance(original, name) }
processor(function as ConeFunctionSymbol)
}
return super.processFunctionsByName(name, processor)
}
private fun enhance(
original: ConeFunctionSymbol,
name: Name
): FirFunctionSymbol {
val firMethod = (original as FirBasedSymbol<*>).fir as? FirJavaMethod ?: error("Can't fake override for $original")
val memberContext = context.copyWithNewDefaultTypeQualifiers(
typeQualifierResolver, jsr305State, firMethod.annotations
)
// TODO: When loading method as an override for a property, all annotations are stick to its getter
// if (this is FirProperty && getter !is FirDefaultPropertyAccessor)
// getter
// else
// this
val predefinedEnhancementInfo =
SignatureBuildingComponents.signature(owner.symbol.classId, firMethod.computeJvmDescriptor()).let { signature ->
PREDEFINED_FUNCTION_ENHANCEMENT_INFO_BY_SIGNATURE[signature]
}
predefinedEnhancementInfo?.let {
assert(it.parametersInfo.size == firMethod.valueParameters.size) {
"Predefined enhancement info for $this has ${it.parametersInfo.size}, but ${firMethod.valueParameters.size} expected"
}
}
val newReceiverTypeRef = if (firMethod.receiverTypeRef != null) enhanceReceiverType(firMethod, memberContext) else null
val newReturnTypeRef = enhanceReturnType(firMethod, memberContext, predefinedEnhancementInfo)
val newValueParameterTypeRefs = mutableListOf<FirResolvedTypeRef>()
for ((index, valueParameter) in firMethod.valueParameters.withIndex()) {
newValueParameterTypeRefs += enhanceValueParameterType(
firMethod, memberContext, predefinedEnhancementInfo, valueParameter as FirJavaValueParameter, index
)
}
val symbol = FirFunctionSymbol(original.callableId)
with(firMethod) {
FirMemberFunctionImpl(
session, null, symbol, name,
newReceiverTypeRef, newReturnTypeRef
).apply {
status = firMethod.status
annotations += firMethod.annotations
valueParameters += firMethod.valueParameters.zip(newValueParameterTypeRefs) { valueParameter, newTypeRef ->
with(valueParameter) {
FirValueParameterImpl(
session, psi,
this.name, newTypeRef,
defaultValue, isCrossinline, isNoinline, isVararg
).apply {
annotations += valueParameter.annotations
}
}
}
}
}
return symbol
}
private fun FirJavaMethod.computeJvmDescriptor(): String = buildString {
append(name.asString()) // TODO: Java constructors
append("(")
for (parameter in valueParameters) {
// TODO: appendErasedType(parameter.returnTypeRef)
}
append(")")
if ((returnTypeRef as FirJavaTypeRef).isVoid()) {
append("V")
} else {
// TODO: appendErasedType(returnTypeRef)
}
}
private fun FirJavaTypeRef.isVoid(): Boolean {
return type is JavaPrimitiveType && type.type == null
}
// ================================================================================================
private fun enhanceReceiverType(
ownerFunction: FirJavaMethod,
memberContext: FirJavaEnhancementContext
): FirResolvedTypeRef {
val signatureParts = ownerFunction.partsForValueParameter(
typeQualifierResolver,
// TODO: check me
parameterContainer = ownerFunction,
methodContext = memberContext
) {
it.receiverTypeRef!!
}.enhance(jsr305State)
return signatureParts.type
}
private val FirTypedDeclaration.valueParameters: List<FirValueParameter> get() = (this as? FirFunction)?.valueParameters.orEmpty()
private fun enhanceValueParameterType(
ownerFunction: FirJavaMethod,
memberContext: FirJavaEnhancementContext,
predefinedEnhancementInfo: PredefinedFunctionEnhancementInfo?,
ownerParameter: FirJavaValueParameter,
index: Int
): FirResolvedTypeRef {
val signatureParts = ownerFunction.partsForValueParameter(
typeQualifierResolver,
parameterContainer = ownerParameter,
methodContext = memberContext
) {
it.valueParameters[index].returnTypeRef
}.enhance(jsr305State, predefinedEnhancementInfo?.parametersInfo?.getOrNull(index))
return signatureParts.type
}
private fun enhanceReturnType(
ownerFunction: FirJavaMethod,
memberContext: FirJavaEnhancementContext,
predefinedEnhancementInfo: PredefinedFunctionEnhancementInfo?
): FirResolvedTypeRef {
val signatureParts = ownerFunction.parts(
typeQualifierResolver,
typeContainer = ownerFunction, isCovariant = true,
containerContext = memberContext,
containerApplicabilityType =
if (false) // TODO: this.safeAs<FirProperty>()?.isJavaField == true
AnnotationTypeQualifierResolver.QualifierApplicabilityType.FIELD
else
AnnotationTypeQualifierResolver.QualifierApplicabilityType.METHOD_RETURN_TYPE
) { it.returnTypeRef }.enhance(jsr305State, predefinedEnhancementInfo?.returnTypeInfo)
return signatureParts.type
}
private fun FirCallableMember.partsForValueParameter(
typeQualifierResolver: FirAnnotationTypeQualifierResolver,
// TODO: investigate if it's really can be a null (check properties' with extension overrides in Java)
parameterContainer: FirAnnotationContainer?,
methodContext: FirJavaEnhancementContext,
collector: (FirCallableMember) -> FirTypeRef
) = parts(
typeQualifierResolver,
parameterContainer, false,
parameterContainer?.let {
methodContext.copyWithNewDefaultTypeQualifiers(typeQualifierResolver, jsr305State, it.annotations)
} ?: methodContext,
AnnotationTypeQualifierResolver.QualifierApplicabilityType.VALUE_PARAMETER,
collector
)
private val overriddenMemberCache = mutableMapOf<FirCallableMember, List<FirCallableMember>>()
private fun FirCallableMember.overriddenMembers(): List<FirCallableMember> {
return overriddenMemberCache.getOrPut(this) {
val result = mutableListOf<FirCallableMember>()
if (this is FirNamedFunction) {
val superTypesScope = useSiteScope.superTypesScope
superTypesScope.processFunctionsByName(this.name) { basicFunctionSymbol ->
val overriddenBy = with(useSiteScope) {
basicFunctionSymbol.getOverridden(setOf(this@overriddenMembers.symbol as ConeFunctionSymbol))
}
val overriddenByFir = (overriddenBy as? FirFunctionSymbol)?.fir
if (overriddenByFir === this@overriddenMembers) {
result += (basicFunctionSymbol as FirFunctionSymbol).fir
}
ProcessorAction.NEXT
}
}
result
}
}
private fun FirCallableMember.parts(
typeQualifierResolver: FirAnnotationTypeQualifierResolver,
typeContainer: FirAnnotationContainer?,
isCovariant: Boolean,
containerContext: FirJavaEnhancementContext,
containerApplicabilityType: AnnotationTypeQualifierResolver.QualifierApplicabilityType,
collector: (FirCallableMember) -> FirTypeRef
): EnhancementSignatureParts {
return EnhancementSignatureParts(
typeQualifierResolver,
typeContainer,
collector(this) as FirJavaTypeRef,
this.overriddenMembers().map {
collector(it)
},
isCovariant,
// recompute default type qualifiers using type annotations
containerContext.copyWithNewDefaultTypeQualifiers(
typeQualifierResolver, jsr305State, collector(this).annotations
),
containerApplicabilityType
)
}
}
@@ -0,0 +1,100 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.java.scopes
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirNamedFunction
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.java.toNotNullConeKotlinType
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
import org.jetbrains.kotlin.fir.scopes.impl.FirAbstractProviderBasedScope
import org.jetbrains.kotlin.fir.scopes.impl.FirClassDeclaredMemberScope
import org.jetbrains.kotlin.fir.symbols.ConeCallableSymbol
import org.jetbrains.kotlin.fir.symbols.ConeFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.name.Name
class JavaClassUseSiteScope(
klass: FirRegularClass,
session: FirSession,
internal val superTypesScope: FirScope,
private val declaredMemberScope: FirClassDeclaredMemberScope
) : FirAbstractProviderBasedScope(session, lookupInFir = true) {
internal val symbol = klass.symbol
//base symbol as key, overridden as value
private val overriddenByBase = mutableMapOf<ConeFunctionSymbol, ConeFunctionSymbol?>()
@Suppress("UNUSED_PARAMETER")
private fun isSubtypeOf(subType: ConeKotlinType, superType: ConeKotlinType): Boolean {
// TODO: introduce normal sub-typing
return true
}
private fun isSubtypeOf(subType: FirTypeRef, superType: FirTypeRef) =
isSubtypeOf(subType.toNotNullConeKotlinType(), superType.toNotNullConeKotlinType())
@Suppress("UNUSED_PARAMETER")
private fun isEqualTypes(a: ConeKotlinType, b: ConeKotlinType): Boolean {
// TODO: introduce normal type comparison
return true
}
private fun isEqualTypes(a: FirTypeRef, b: FirTypeRef) =
isEqualTypes(a.toNotNullConeKotlinType(), b.toNotNullConeKotlinType())
private fun isOverriddenFunCheck(member: FirNamedFunction, self: FirNamedFunction): Boolean {
return member.valueParameters.size == self.valueParameters.size &&
member.valueParameters.zip(self.valueParameters).all { (memberParam, selfParam) ->
isEqualTypes(memberParam.returnTypeRef, selfParam.returnTypeRef)
}
}
internal fun ConeFunctionSymbol.getOverridden(candidates: Set<ConeFunctionSymbol>): ConeCallableSymbol? {
if (overriddenByBase.containsKey(this)) return overriddenByBase[this]
fun sameReceivers(memberTypeRef: FirTypeRef?, selfTypeRef: FirTypeRef?): Boolean {
return when {
memberTypeRef != null && selfTypeRef != null -> isEqualTypes(memberTypeRef, selfTypeRef)
else -> memberTypeRef == null && selfTypeRef == null
}
}
val self = (this as FirFunctionSymbol).fir as FirNamedFunction
val overriding = candidates.firstOrNull {
val member = (it as FirFunctionSymbol).fir as FirNamedFunction
self.modality != Modality.FINAL
&& sameReceivers(member.receiverTypeRef, self.receiverTypeRef)
&& isSubtypeOf(member.returnTypeRef, self.returnTypeRef)
&& isOverriddenFunCheck(member, self)
} // TODO: two or more overrides for one fun?
overriddenByBase[this] = overriding
return overriding
}
override fun processFunctionsByName(name: Name, processor: (ConeFunctionSymbol) -> ProcessorAction): ProcessorAction {
val overrideCandidates = mutableSetOf<ConeFunctionSymbol>()
if (!declaredMemberScope.processFunctionsByName(name) {
overrideCandidates += it
processor(it)
}
) return ProcessorAction.STOP
return superTypesScope.processFunctionsByName(name) {
val overriddenBy = it.getOverridden(overrideCandidates)
if (overriddenBy == null) {
processor(it)
} else {
ProcessorAction.NEXT
}
}
}
}
@@ -0,0 +1,20 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.java.scopes
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.java.declarations.FirJavaClass
import org.jetbrains.kotlin.fir.resolve.FirScopeProvider
import org.jetbrains.kotlin.fir.scopes.FirScope
class JavaFirScopeProvider : FirScopeProvider {
override fun getDeclaredMemberScope(klass: FirRegularClass, session: FirSession): FirScope {
if (klass !is FirJavaClass) return FirScopeProvider.emptyScope
return JavaClassEnhancementScope(session, klass.useSiteScope)
}
}
@@ -6,9 +6,7 @@
package org.jetbrains.kotlin.fir
import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.fir.resolve.FirProvider
import org.jetbrains.kotlin.fir.resolve.FirQualifierResolver
import org.jetbrains.kotlin.fir.resolve.FirTypeResolver
import org.jetbrains.kotlin.fir.resolve.*
import org.jetbrains.kotlin.fir.resolve.impl.*
abstract class FirModuleBasedSession(override val moduleInfo: ModuleInfo) : FirSessionBase() {
@@ -19,3 +17,4 @@ abstract class FirModuleBasedSession(override val moduleInfo: ModuleInfo) : FirS
registerComponent(FirTypeResolver::class, FirTypeResolverImpl(this))
}
}
@@ -8,6 +8,8 @@ package org.jetbrains.kotlin.fir.resolve
import org.jetbrains.kotlin.fir.symbols.CallableId
import org.jetbrains.kotlin.fir.symbols.ConeCallableSymbol
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
import org.jetbrains.kotlin.fir.visitors.FirTransformer
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
@@ -38,4 +40,16 @@ abstract class AbstractFirSymbolProvider : FirSymbolProvider {
calculated.first
}
}
fun <D> transformTopLevelClasses(transformer: FirTransformer<D>, data: D) {
val symbols = classCache.values.filterNotNullTo(mutableListOf())
// TODO: do something with new symbols which can be found during transformation of another symbols
for (symbol in symbols) {
if (symbol !is FirClassSymbol) continue
if (symbol.classId.relativeClassName.parent().isRoot) {
// Launch for top-level classes only
symbol.fir.transform(transformer, data)
}
}
}
}
@@ -0,0 +1,18 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.resolve
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.scopes.FirScope
interface FirScopeProvider {
fun getDeclaredMemberScope(klass: FirRegularClass, session: FirSession): FirScope
companion object {
val emptyScope = object : FirScope {}
}
}
@@ -45,7 +45,7 @@ fun ConeClassifierLookupTag.toSymbol(useSiteSession: FirSession): ConeClassifier
}
fun ConeClassifierSymbol.constructType(typeArguments: Array<ConeKotlinTypeProjection>, isNullable: Boolean): ConeKotlinType {
fun ConeClassifierSymbol.constructType(typeArguments: Array<ConeKotlinTypeProjection>, isNullable: Boolean): ConeLookupTagBasedType {
return when (this) {
is ConeTypeParameterSymbol -> {
ConeTypeParameterTypeImpl(this, isNullable)
@@ -0,0 +1,86 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.resolve
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.expandedConeType
import org.jetbrains.kotlin.fir.declarations.superConeTypes
import org.jetbrains.kotlin.fir.symbols.ConeClassifierSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol
import org.jetbrains.kotlin.fir.types.ConeAbbreviatedType
import org.jetbrains.kotlin.fir.types.ConeClassErrorType
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
fun lookupSuperTypes(
klass: FirRegularClass,
lookupInterfaces: Boolean,
deep: Boolean,
useSiteSession: FirSession
): List<ConeClassLikeType> {
return mutableListOf<ConeClassLikeType>().also {
if (lookupInterfaces) klass.symbol.collectSuperTypes(it, deep, useSiteSession)
else klass.symbol.collectSuperClasses(it, useSiteSession)
}
}
private tailrec fun ConeClassLikeType.computePartialExpansion(useSiteSession: FirSession): ConeClassLikeType? {
return when (this) {
is ConeAbbreviatedType -> directExpansionType(useSiteSession)?.computePartialExpansion(useSiteSession)
else -> this
}
}
private tailrec fun ConeClassifierSymbol.collectSuperClasses(
list: MutableList<ConeClassLikeType>,
useSiteSession: FirSession
) {
when (this) {
is FirClassSymbol -> {
val superClassType =
fir.superConeTypes
.map { it.computePartialExpansion(useSiteSession) }
.firstOrNull {
it !is ConeClassErrorType &&
(it?.lookupTag?.toSymbol(useSiteSession) as? FirClassSymbol)?.fir?.classKind == ClassKind.CLASS
} ?: return
list += superClassType
superClassType.lookupTag.toSymbol(useSiteSession)?.collectSuperClasses(list, useSiteSession)
}
is FirTypeAliasSymbol -> {
val expansion = fir.expandedConeType?.computePartialExpansion(useSiteSession) ?: return
expansion.lookupTag.toSymbol(useSiteSession)?.collectSuperClasses(list, useSiteSession)
}
else -> error("?!id:1")
}
}
private fun ConeClassifierSymbol.collectSuperTypes(
list: MutableList<ConeClassLikeType>,
deep: Boolean,
useSiteSession: FirSession
) {
when (this) {
is FirClassSymbol -> {
val superClassTypes =
fir.superConeTypes.mapNotNull { it.computePartialExpansion(useSiteSession) }
list += superClassTypes
if (deep)
superClassTypes.forEach {
if (it !is ConeClassErrorType) {
it.lookupTag.toSymbol(useSiteSession)?.collectSuperTypes(list, deep, useSiteSession)
}
}
}
is FirTypeAliasSymbol -> {
val expansion = fir.expandedConeType?.computePartialExpansion(useSiteSession) ?: return
expansion.lookupTag.toSymbol(useSiteSession)?.collectSuperTypes(list, deep, useSiteSession)
}
else -> error("?!id:1")
}
}
@@ -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) })
}
}
@@ -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)
}
}
@@ -5,23 +5,9 @@
package org.jetbrains.kotlin.fir.resolve.transformers
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.expandedConeType
import org.jetbrains.kotlin.fir.declarations.superConeTypes
import org.jetbrains.kotlin.fir.resolve.directExpansionType
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.scopes.impl.FirCompositeScope
import org.jetbrains.kotlin.fir.scopes.impl.FirMemberTypeParameterScope
import org.jetbrains.kotlin.fir.symbols.ConeClassifierSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol
import org.jetbrains.kotlin.fir.types.ConeAbbreviatedType
import org.jetbrains.kotlin.fir.types.ConeClassErrorType
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
abstract class FirAbstractTreeTransformerWithSuperTypes(reversedScopePriority: Boolean) : FirAbstractTreeTransformer() {
protected val towerScope = FirCompositeScope(mutableListOf(), reversedPriority = reversedScopePriority)
@@ -37,74 +23,6 @@ abstract class FirAbstractTreeTransformerWithSuperTypes(reversedScopePriority: B
return result
}
protected fun lookupSuperTypes(
klass: FirRegularClass,
lookupInterfaces: Boolean,
deep: Boolean,
useSiteSession: FirSession
): List<ConeClassLikeType> {
return mutableListOf<ConeClassLikeType>().also {
if (lookupInterfaces) klass.symbol.collectSuperTypes(it, deep, useSiteSession)
else klass.symbol.collectSuperClasses(it, useSiteSession)
}
}
private tailrec fun ConeClassLikeType.computePartialExpansion(useSiteSession: FirSession): ConeClassLikeType? {
return when (this) {
is ConeAbbreviatedType -> directExpansionType(useSiteSession)?.computePartialExpansion(useSiteSession)
else -> this
}
}
private tailrec fun ConeClassifierSymbol.collectSuperClasses(
list: MutableList<ConeClassLikeType>,
useSiteSession: FirSession
) {
when (this) {
is FirClassSymbol -> {
val superClassType =
fir.superConeTypes
.map { it.computePartialExpansion(useSiteSession) }
.firstOrNull {
it !is ConeClassErrorType &&
(it?.lookupTag?.toSymbol(useSiteSession) as? FirClassSymbol)?.fir?.classKind == ClassKind.CLASS
} ?: return
list += superClassType
superClassType.lookupTag.toSymbol(useSiteSession)?.collectSuperClasses(list, useSiteSession)
}
is FirTypeAliasSymbol -> {
val expansion = fir.expandedConeType?.computePartialExpansion(useSiteSession) ?: return
expansion.lookupTag.toSymbol(useSiteSession)?.collectSuperClasses(list, useSiteSession)
}
else -> error("?!id:1")
}
}
private fun ConeClassifierSymbol.collectSuperTypes(
list: MutableList<ConeClassLikeType>,
deep: Boolean,
useSiteSession: FirSession
) {
when (this) {
is FirClassSymbol -> {
val superClassTypes =
fir.superConeTypes.mapNotNull { it.computePartialExpansion(useSiteSession) }
list += superClassTypes
if (deep)
superClassTypes.forEach {
if (it !is ConeClassErrorType) {
it.lookupTag.toSymbol(useSiteSession)?.collectSuperTypes(list, deep, useSiteSession)
}
}
}
is FirTypeAliasSymbol -> {
val expansion = fir.expandedConeType?.computePartialExpansion(useSiteSession) ?: return
expansion.lookupTag.toSymbol(useSiteSession)?.collectSuperTypes(list, deep, useSiteSession)
}
else -> error("?!id:1")
}
}
protected fun FirMemberDeclaration.addTypeParametersScope() {
val scopes = towerScope.scopes
if (typeParameters.isNotEmpty()) {
@@ -14,10 +14,13 @@ import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
import org.jetbrains.kotlin.fir.references.FirResolvedCallableReferenceImpl
import org.jetbrains.kotlin.fir.resolve.FirScopeProvider
import org.jetbrains.kotlin.fir.resolve.lookupSuperTypes
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
import org.jetbrains.kotlin.fir.scopes.ProcessorAction.NEXT
import org.jetbrains.kotlin.fir.scopes.impl.*
import org.jetbrains.kotlin.fir.service
import org.jetbrains.kotlin.fir.symbols.ConeCallableSymbol
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
@@ -53,7 +56,7 @@ class FirAccessResolveTransformer : FirAbstractTreeTransformerWithSuperTypes(rev
private fun FirRegularClass.buildUseSiteScope(useSiteSession: FirSession = session): FirClassUseSiteScope {
val superTypeScope = FirCompositeScope(mutableListOf())
val declaredScope = FirClassDeclaredMemberScope(this, useSiteSession)
val declaredScope = useSiteSession.service<FirScopeProvider>().getDeclaredMemberScope(this, useSiteSession)
lookupSuperTypes(this, lookupInterfaces = true, deep = false, useSiteSession = useSiteSession)
.mapNotNullTo(superTypeScope.scopes) { useSiteSuperType ->
if (useSiteSuperType is ConeClassErrorType) return@mapNotNullTo null
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.render
import org.jetbrains.kotlin.fir.resolve.FirProvider
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
import org.jetbrains.kotlin.fir.resolve.lookupSuperTypes
import org.jetbrains.kotlin.fir.scopes.FirPosition
import org.jetbrains.kotlin.fir.scopes.addImportingScopes
import org.jetbrains.kotlin.fir.scopes.impl.*
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.resolve.FirProvider
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
import org.jetbrains.kotlin.fir.resolve.lookupSuperTypes
import org.jetbrains.kotlin.fir.scopes.FirPosition
import org.jetbrains.kotlin.fir.scopes.addImportingScopes
import org.jetbrains.kotlin.fir.scopes.impl.*
@@ -11,7 +11,8 @@ import org.jetbrains.kotlin.fir.resolve.impl.FirCompositeSymbolProvider
import org.jetbrains.kotlin.fir.resolve.impl.FirDependenciesSymbolProviderImpl
import org.jetbrains.kotlin.fir.scopes.FirScope
abstract class FirAbstractProviderBasedScope(val session: FirSession, lookupInFir: Boolean = true) : FirScope {
abstract class FirAbstractProviderBasedScope(val session: FirSession, lookupInFir: Boolean = true) :
FirScope {
val provider = when (val symbolProvider = FirSymbolProvider.getInstance(session)) {
is FirCompositeSymbolProvider -> symbolProvider.takeIf { !lookupInFir }?.providers?.find {
it is FirDependenciesSymbolProviderImpl
@@ -56,6 +56,10 @@ class FirRenderer(builder: StringBuilder) : FirVisitorVoid() {
printer.popIndent()
}
fun newLine() {
println()
}
override fun visitElement(element: FirElement) {
element.acceptChildren(this)
}
@@ -214,22 +218,32 @@ class FirRenderer(builder: StringBuilder) : FirVisitorVoid() {
}
private fun FirDeclarationContainer.renderDeclarations() {
renderInBraces {
for (declaration in declarations) {
declaration.accept(this@FirRenderer)
println()
}
}
}
fun renderInBraces(f: () -> Unit) {
println(" {")
pushIndent()
for (declaration in declarations) {
declaration.accept(this@FirRenderer)
println()
}
f()
popIndent()
println("}")
}
override fun visitRegularClass(regularClass: FirRegularClass) {
visitMemberDeclaration(regularClass)
fun renderSupertypes(regularClass: FirRegularClass) {
if (regularClass.superTypeRefs.isNotEmpty()) {
print(" : ")
regularClass.superTypeRefs.renderSeparated()
}
}
override fun visitRegularClass(regularClass: FirRegularClass) {
visitMemberDeclaration(regularClass)
renderSupertypes(regularClass)
regularClass.renderDeclarations()
}
@@ -345,14 +359,12 @@ class FirRenderer(builder: StringBuilder) : FirVisitorVoid() {
}
override fun visitBlock(block: FirBlock) {
println(" {")
pushIndent()
for (statement in block.statements) {
statement.accept(this)
println()
renderInBraces {
for (statement in block.statements) {
statement.accept(this)
println()
}
}
popIndent()
println("}")
}
override fun visitTypeAlias(typeAlias: FirTypeAlias) {
@@ -657,8 +669,10 @@ class FirRenderer(builder: StringBuilder) : FirVisitorVoid() {
buildString {
append("ft<")
append(lowerBound.asString())
append(lowerBound.nullability.suffix)
append(", ")
append(upperBound.asString())
append(upperBound.nullability.suffix)
append(">")
}
}
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.fir
import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.utils.Jsr305State
import kotlin.reflect.KClass
interface FirSession {
@@ -13,6 +14,8 @@ interface FirSession {
val sessionProvider: FirSessionProvider? get() = null
val jsr305State: Jsr305State? get() = null
val components: Map<KClass<*>, Any>
fun <T : Any> getService(kclass: KClass<T>): T =
@@ -29,6 +29,30 @@ fun <T : FirElement, D> MutableList<T>.transformInplace(transformer: FirTransfor
}
}
fun <T : FirElement, D> MutableList<T>.transformInplaceWithBeforeOperation(
transformer: FirTransformer<D>, data: D, operation: (T, Int) -> Unit
) {
val iterator = this.listIterator()
var index = 0
while (iterator.hasNext()) {
val next = iterator.next()
operation(next, index++)
val result = next.transform<T, D>(transformer, data)
if (result.isSingle) {
iterator.set(result.single)
} else {
val resultIterator = result.list.listIterator()
if (!resultIterator.hasNext()) {
iterator.remove()
} else {
iterator.set(resultIterator.next())
}
while (resultIterator.hasNext()) {
iterator.add(resultIterator.next())
}
}
}
}
fun <T : FirElement, D> T.transformSingle(transformer: FirTransformer<D>, data: D): T {
return this.transform<T, D>(transformer, data).single
@@ -7,8 +7,11 @@ package org.jetbrains.kotlin.fir.expressions
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
import org.jetbrains.kotlin.fir.BaseTransformedType
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.fir.visitors.FirVisitor
import org.jetbrains.kotlin.name.FqName
@BaseTransformedType
interface FirAnnotationCall : FirCall {
@@ -24,4 +27,7 @@ interface FirAnnotationCall : FirCall {
annotationTypeRef.accept(visitor, data)
super.acceptChildren(visitor, data)
}
}
}
val FirAnnotationCall.resolvedFqName: FqName?
get() = ((annotationTypeRef as? FirResolvedTypeRef)?.type as? ConeClassLikeType)?.lookupTag?.classId?.asSingleFqName()
@@ -5,9 +5,19 @@
package org.jetbrains.kotlin.fir.expressions
import org.jetbrains.kotlin.fir.FirResolvedCallableReference
import org.jetbrains.kotlin.fir.symbols.ConeCallableSymbol
import org.jetbrains.kotlin.fir.visitors.FirVisitor
interface FirExpression : FirStatement {
override fun <R, D> accept(visitor: FirVisitor<R, D>, data: D): R =
visitor.visitExpression(this, data)
}
fun FirExpression.toResolvedCallableReference(): FirResolvedCallableReference? {
return (this as? FirQualifiedAccess)?.calleeReference as? FirResolvedCallableReference
}
fun FirExpression.toResolvedCallableSymbol(): ConeCallableSymbol? {
return toResolvedCallableReference()?.callableSymbol
}
@@ -213,14 +213,22 @@ object JavaToKotlinClassMap : PlatformToKotlinClassMap {
emptySet<ClassDescriptor>()
}
fun isMutable(mutable: ClassDescriptor): Boolean = mutableToReadOnly.containsKey(DescriptorUtils.getFqName(mutable))
fun mutableToReadOnly(fqNameUnsafe: FqNameUnsafe?): FqName? = mutableToReadOnly[fqNameUnsafe]
fun readOnlyToMutable(fqNameUnsafe: FqNameUnsafe?): FqName? = readOnlyToMutable[fqNameUnsafe]
fun isMutable(fqNameUnsafe: FqNameUnsafe?): Boolean = mutableToReadOnly.containsKey(fqNameUnsafe)
fun isMutable(mutable: ClassDescriptor): Boolean = isMutable(DescriptorUtils.getFqName(mutable))
fun isMutable(type: KotlinType): Boolean {
val classDescriptor = TypeUtils.getClassDescriptor(type)
return classDescriptor != null && isMutable(classDescriptor)
}
fun isReadOnly(readOnly: ClassDescriptor): Boolean = readOnlyToMutable.containsKey(DescriptorUtils.getFqName(readOnly))
fun isReadOnly(fqNameUnsafe: FqNameUnsafe?): Boolean = readOnlyToMutable.containsKey(fqNameUnsafe)
fun isReadOnly(readOnly: ClassDescriptor): Boolean = isReadOnly(DescriptorUtils.getFqName(readOnly))
fun isReadOnly(type: KotlinType): Boolean {
val classDescriptor = TypeUtils.getClassDescriptor(type)
@@ -34,13 +34,13 @@ import org.jetbrains.kotlin.utils.Jsr305State
import org.jetbrains.kotlin.utils.ReportLevel
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
private val TYPE_QUALIFIER_NICKNAME_FQNAME = FqName("javax.annotation.meta.TypeQualifierNickname")
private val TYPE_QUALIFIER_FQNAME = FqName("javax.annotation.meta.TypeQualifier")
private val TYPE_QUALIFIER_DEFAULT_FQNAME = FqName("javax.annotation.meta.TypeQualifierDefault")
val TYPE_QUALIFIER_NICKNAME_FQNAME = FqName("javax.annotation.meta.TypeQualifierNickname")
val TYPE_QUALIFIER_FQNAME = FqName("javax.annotation.meta.TypeQualifier")
val TYPE_QUALIFIER_DEFAULT_FQNAME = FqName("javax.annotation.meta.TypeQualifierDefault")
private val MIGRATION_ANNOTATION_FQNAME = FqName("kotlin.annotations.jvm.UnderMigration")
val MIGRATION_ANNOTATION_FQNAME = FqName("kotlin.annotations.jvm.UnderMigration")
private val BUILT_IN_TYPE_QUALIFIER_DEFAULT_ANNOTATIONS = mapOf(
val BUILT_IN_TYPE_QUALIFIER_DEFAULT_ANNOTATIONS = mapOf(
FqName("javax.annotation.ParametersAreNullableByDefault") to
NullabilityQualifierWithApplicability(
NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NULLABLE),
@@ -93,9 +93,9 @@ interface JavaResolverSettings {
}
}
private typealias QualifierByApplicabilityType = EnumMap<AnnotationTypeQualifierResolver.QualifierApplicabilityType, NullabilityQualifierWithMigrationStatus?>
typealias QualifierByApplicabilityType = EnumMap<AnnotationTypeQualifierResolver.QualifierApplicabilityType, NullabilityQualifierWithMigrationStatus?>
class JavaTypeQualifiersByElementType(internal val nullabilityQualifiers: QualifierByApplicabilityType) {
class JavaTypeQualifiersByElementType(val nullabilityQualifiers: QualifierByApplicabilityType) {
operator fun get(applicabilityType: AnnotationTypeQualifierResolver.QualifierApplicabilityType?): JavaTypeQualifiers? {
val nullabilityQualifierWithMigrationStatus = nullabilityQualifiers[applicabilityType] ?: return null
@@ -462,7 +462,7 @@ class SignatureEnhancement(
}
}
private fun createJavaTypeQualifiers(
fun createJavaTypeQualifiers(
nullability: NullabilityQualifier?,
mutability: MutabilityQualifier?,
forWarning: Boolean,
@@ -474,7 +474,7 @@ private fun createJavaTypeQualifiers(
return JavaTypeQualifiers(nullability, mutability, true, forWarning)
}
private fun <T : Any> Set<T>.select(low: T, high: T, own: T?, isCovariant: Boolean): T? {
fun <T : Any> Set<T>.select(low: T, high: T, own: T?, isCovariant: Boolean): T? {
if (isCovariant) {
val supertypeQualifier = if (low in this) low else if (high in this) high else null
return if (supertypeQualifier == low && own == high) null else own ?: supertypeQualifier
@@ -488,7 +488,7 @@ private fun <T : Any> Set<T>.select(low: T, high: T, own: T?, isCovariant: Boole
return effectiveSet.singleOrNull()
}
private fun Set<NullabilityQualifier>.select(own: NullabilityQualifier?, isCovariant: Boolean) =
fun Set<NullabilityQualifier>.select(own: NullabilityQualifier?, isCovariant: Boolean) =
if (own == NullabilityQualifier.FORCE_FLEXIBILITY)
NullabilityQualifier.FORCE_FLEXIBILITY
else
@@ -45,7 +45,7 @@ fun KotlinType.enhance(qualifiers: (Int) -> JavaTypeQualifiers) = unwrap().enhan
fun KotlinType.hasEnhancedNullability()
= annotations.findAnnotation(JvmAnnotationNames.ENHANCED_NULLABILITY_ANNOTATION) != null
private enum class TypeComponentPosition {
enum class TypeComponentPosition {
FLEXIBLE_LOWER,
FLEXIBLE_UPPER,
INFLEXIBLE
@@ -147,7 +147,7 @@ private fun List<Annotations>.compositeAnnotationsOrSingle() = when (size) {
else -> CompositeAnnotations(this.toList())
}
private fun TypeComponentPosition.shouldEnhance() = this != TypeComponentPosition.INFLEXIBLE
fun TypeComponentPosition.shouldEnhance() = this != TypeComponentPosition.INFLEXIBLE
private data class EnhancementResult<out T>(val result: T, val enhancementAnnotations: Annotations?)
private fun <T> T.noChange() = EnhancementResult(this, null)
@@ -27,11 +27,11 @@ enum class MutabilityQualifier {
MUTABLE
}
class JavaTypeQualifiers internal constructor(
val nullability: NullabilityQualifier?,
val mutability: MutabilityQualifier?,
internal val isNotNullTypeParameter: Boolean,
internal val isNullabilityQualifierForWarning: Boolean = false
class JavaTypeQualifiers(
val nullability: NullabilityQualifier?,
val mutability: MutabilityQualifier?,
val isNotNullTypeParameter: Boolean,
val isNullabilityQualifierForWarning: Boolean = false
) {
companion object {
val NONE = JavaTypeQualifiers(null, null, false)
@@ -0,0 +1,4 @@
public open class Annotated : R|java/lang/Object| {
@R|org/jetbrains/annotations/NotNull|() public open operator function foo(@R|org/jetbrains/annotations/Nullable|() param: R|ft<java/lang/String?, java/lang/String?>|?): R|ft<java/lang/String, java/lang/String>|
}
@@ -0,0 +1,10 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class Annotated {
@NotNull
public String foo(@Nullable String param) {
if (param != null) return param;
else return "";
}
}
@@ -0,0 +1,6 @@
class User : Annotated() {
fun test() {
val x = foo("123")
val y = foo(null)
}
}
@@ -0,0 +1,10 @@
FILE: jvm.kt
public final class User : R|Annotated| {
public constructor(): super<R|Annotated|>()
public final function test(): R|kotlin/Unit| {
val x: R|error: Not supported: FirImplicitTypeRefImpl| = R|/Annotated.foo|(String(123))
val y: R|error: Not supported: FirImplicitTypeRefImpl| = R|/Annotated.foo|(Null(null))
}
}
@@ -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>|
}
@@ -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,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?>|!
}
@@ -7,7 +7,7 @@ FILE: simpleFakeOverride.kt
public constructor(): super<R|A<Some>|>()
public final function test(): R|kotlin/Unit| {
R|FakeOverride</A.foo: R|ft<T, T>|!>|(<Unresolved name: Some>#())
R|FakeOverride</A.foo: R|ft<T, T?>|!>|(<Unresolved name: Some>#())
}
}
@@ -0,0 +1,6 @@
public open class Some : R|java/lang/Object| {
public open operator function foo(param: R|kotlin/Int|): R|kotlin/Boolean|
public open operator function bar(arr: R|kotlin/IntArray|): R|kotlin/Array<ft<java/lang/String, java/lang/String?>>|
}
@@ -0,0 +1,14 @@
public class Some {
public boolean foo(int param) {
return param > 0;
}
public String[] bar(int[] arr) {
String[] result = new String[arr.length];
int i = 0;
for (int elem: arr) {
result[i++] = elem;
}
return result;
}
}
@@ -0,0 +1,7 @@
class A : Some() {
fun test() {
val res1 = foo(1)
val res2 = foo(-1)
val res3 = bar(intArrayOf(0, 2, -2))
}
}
@@ -0,0 +1,11 @@
FILE: jvm.kt
public final class A : R|Some| {
public constructor(): super<R|Some|>()
public final function test(): R|kotlin/Unit| {
val res1: R|error: Not supported: FirImplicitTypeRefImpl| = R|/Some.foo|(Int(1))
val res2: R|error: Not supported: FirImplicitTypeRefImpl| = R|/Some.foo|(<Unresolved name: unaryMinus>#(Int(1)))
val res3: R|error: Not supported: FirImplicitTypeRefImpl| = R|/Some.bar|(<Unresolved name: intArrayOf>#(Int(0), Int(2), <Unresolved name: unaryMinus>#(Int(2))))
}
}
@@ -0,0 +1,6 @@
public open class A : R|java/lang/Object| {
public open operator function foo(): R|ft<A, A?>|!
public open operator function bar(): R|ft<A, A?>|!
}
@@ -12,15 +12,26 @@ import com.intellij.psi.PsiManager
import com.intellij.psi.search.FileTypeIndex
import org.jetbrains.kotlin.fir.FirRenderer
import org.jetbrains.kotlin.fir.builder.RawFirBuilder
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.dependenciesWithoutSelf
import org.jetbrains.kotlin.fir.java.FirJavaModuleBasedSession
import org.jetbrains.kotlin.fir.java.FirLibrarySession
import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider
import org.jetbrains.kotlin.fir.java.JavaSymbolProvider
import org.jetbrains.kotlin.fir.java.declarations.FirJavaClass
import org.jetbrains.kotlin.fir.java.declarations.FirJavaMethod
import org.jetbrains.kotlin.fir.java.scopes.JavaClassEnhancementScope
import org.jetbrains.kotlin.fir.resolve.FirProvider
import org.jetbrains.kotlin.fir.resolve.FirScopeProvider
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
import org.jetbrains.kotlin.fir.resolve.impl.FirCompositeSymbolProvider
import org.jetbrains.kotlin.fir.resolve.impl.FirProviderImpl
import org.jetbrains.kotlin.fir.resolve.transformers.FirTotalResolveTransformer
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
import org.jetbrains.kotlin.fir.scopes.impl.FirCompositeScope
import org.jetbrains.kotlin.fir.service
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo
import org.jetbrains.kotlin.idea.caches.project.isLibraryClasses
@@ -64,9 +75,11 @@ abstract class AbstractFirMultiModuleResolveTest : AbstractMultiModuleTest() {
private fun doFirResolveTest(dirPath: String) {
val firFiles = mutableListOf<FirFile>()
val sessions = mutableListOf<FirJavaModuleBasedSession>()
val provider = FirProjectSessionProvider(project)
for (module in project.allModules().drop(1)) {
val session = createSession(module, provider)
sessions += session
val builder = RawFirBuilder(session, stubMode = false)
val psiManager = PsiManager.getInstance(project)
@@ -112,5 +125,54 @@ abstract class AbstractFirMultiModuleResolveTest : AbstractMultiModuleTest() {
val expectedPath = expectedTxtPath((file.psi as PsiFile).virtualFile)
KotlinTestUtils.assertEqualsToFile(File(expectedPath), firFileDump)
}
val processedJavaClasses = mutableSetOf<FirJavaClass>()
val javaFirDump = StringBuilder().also { builder ->
val renderer = FirRenderer(builder)
for (session in sessions) {
val symbolProvider = session.service<FirSymbolProvider>() as FirCompositeSymbolProvider
val javaProvider = symbolProvider.providers.filterIsInstance<JavaSymbolProvider>().first()
for (javaClass in javaProvider.getJavaTopLevelClasses().sortedBy { it.name }) {
if (javaClass !is FirJavaClass || javaClass in processedJavaClasses) continue
val enhancementScope = session.service<FirScopeProvider>().getDeclaredMemberScope(javaClass, session).let {
when (it) {
is FirCompositeScope -> it.scopes.filterIsInstance<JavaClassEnhancementScope>().first()
is JavaClassEnhancementScope -> it
else -> null
}
}
if (enhancementScope == null) {
javaClass.accept(renderer, null)
} else {
renderer.visitMemberDeclaration(javaClass)
renderer.renderSupertypes(javaClass)
renderer.renderInBraces {
val renderedDeclarations = mutableListOf<FirDeclaration>()
for (declaration in javaClass.declarations) {
if (declaration in renderedDeclarations) continue
if (declaration !is FirJavaMethod) {
declaration.accept(renderer, null)
renderer.newLine()
renderedDeclarations += declaration
} else {
enhancementScope.processFunctionsByName(declaration.name) { symbol ->
val enhanced = (symbol as? FirFunctionSymbol)?.fir
if (enhanced != null && enhanced !in renderedDeclarations) {
enhanced.accept(renderer, null)
renderer.newLine()
renderedDeclarations += enhanced
}
ProcessorAction.NEXT
}
}
}
}
}
processedJavaClasses += javaClass
}
}
}.toString()
if (javaFirDump.isNotEmpty()) {
KotlinTestUtils.assertEqualsToFile(File("$dirPath/extraDump.java.txt"), javaFirDump)
}
}
}
@@ -34,6 +34,16 @@ public class FirMultiModuleResolveTestGenerated extends AbstractFirMultiModuleRe
runTest("idea/testData/fir/multiModule/basic/");
}
@TestMetadata("basicWithAnnotatedJava")
public void testBasicWithAnnotatedJava() throws Exception {
runTest("idea/testData/fir/multiModule/basicWithAnnotatedJava/");
}
@TestMetadata("basicWithAnnotatedOverriddenJava")
public void testBasicWithAnnotatedOverriddenJava() throws Exception {
runTest("idea/testData/fir/multiModule/basicWithAnnotatedOverriddenJava/");
}
@TestMetadata("basicWithJava")
public void testBasicWithJava() throws Exception {
runTest("idea/testData/fir/multiModule/basicWithJava/");
@@ -44,6 +54,11 @@ public class FirMultiModuleResolveTestGenerated extends AbstractFirMultiModuleRe
runTest("idea/testData/fir/multiModule/basicWithJavaFakeOverride/");
}
@TestMetadata("basicWithPrimitiveJava")
public void testBasicWithPrimitiveJava() throws Exception {
runTest("idea/testData/fir/multiModule/basicWithPrimitiveJava/");
}
@TestMetadata("mppFakeOverrides")
public void testMppFakeOverrides() throws Exception {
runTest("idea/testData/fir/multiModule/mppFakeOverrides/");