FIR Java: support Kotlin extension overriding: at last, #KT-29937 Fixed
This commit is contained in:
+34
-10
@@ -81,7 +81,7 @@ class JavaClassEnhancementScope(
|
|||||||
val firField = (original as FirBasedSymbol<*>).fir as? FirJavaField ?: error("Can't make enhancement for $original")
|
val firField = (original as FirBasedSymbol<*>).fir as? FirJavaField ?: error("Can't make enhancement for $original")
|
||||||
|
|
||||||
val memberContext = context.copyWithNewDefaultTypeQualifiers(typeQualifierResolver, jsr305State, firField.annotations)
|
val memberContext = context.copyWithNewDefaultTypeQualifiers(typeQualifierResolver, jsr305State, firField.annotations)
|
||||||
val newReturnTypeRef = enhanceReturnType(firField, memberContext, null)
|
val newReturnTypeRef = enhanceReturnType(firField, emptyList(), memberContext, null)
|
||||||
|
|
||||||
val symbol = FirPropertySymbol(original.callableId)
|
val symbol = FirPropertySymbol(original.callableId)
|
||||||
with(firField) {
|
with(firField) {
|
||||||
@@ -124,20 +124,26 @@ class JavaClassEnhancementScope(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val newReceiverTypeRef = if (firMethod is FirJavaMethod && firMethod.receiverTypeRef != null) {
|
val overriddenMembers = firMethod.overriddenMembers()
|
||||||
enhanceReceiverType(firMethod, memberContext)
|
val hasReceiver = overriddenMembers.any { it.receiverTypeRef != null }
|
||||||
|
|
||||||
|
val newReceiverTypeRef = if (firMethod is FirJavaMethod && hasReceiver) {
|
||||||
|
enhanceReceiverType(firMethod, overriddenMembers, memberContext)
|
||||||
} else null
|
} else null
|
||||||
val newReturnTypeRef = if (firMethod is FirJavaConstructor) {
|
val newReturnTypeRef = if (firMethod is FirJavaConstructor) {
|
||||||
firMethod.returnTypeRef
|
firMethod.returnTypeRef
|
||||||
} else {
|
} else {
|
||||||
enhanceReturnType(firMethod, memberContext, predefinedEnhancementInfo)
|
enhanceReturnType(firMethod, overriddenMembers, memberContext, predefinedEnhancementInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
val newValueParameterInfo = mutableListOf<EnhanceValueParameterResult>()
|
val newValueParameterInfo = mutableListOf<EnhanceValueParameterResult>()
|
||||||
|
|
||||||
for ((index, valueParameter) in firMethod.valueParameters.withIndex()) {
|
for ((index, valueParameter) in firMethod.valueParameters.withIndex()) {
|
||||||
|
if (hasReceiver && index == 0) continue
|
||||||
newValueParameterInfo += enhanceValueParameter(
|
newValueParameterInfo += enhanceValueParameter(
|
||||||
firMethod, memberContext, predefinedEnhancementInfo, valueParameter as FirJavaValueParameter, index
|
firMethod, overriddenMembers, hasReceiver,
|
||||||
|
memberContext, predefinedEnhancementInfo, valueParameter as FirJavaValueParameter,
|
||||||
|
if (hasReceiver) index - 1 else index
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,10 +219,12 @@ class JavaClassEnhancementScope(
|
|||||||
|
|
||||||
private fun enhanceReceiverType(
|
private fun enhanceReceiverType(
|
||||||
ownerFunction: FirJavaMethod,
|
ownerFunction: FirJavaMethod,
|
||||||
|
overriddenMembers: List<FirCallableMember>,
|
||||||
memberContext: FirJavaEnhancementContext
|
memberContext: FirJavaEnhancementContext
|
||||||
): FirResolvedTypeRef {
|
): FirResolvedTypeRef {
|
||||||
val signatureParts = ownerFunction.partsForValueParameter(
|
val signatureParts = ownerFunction.partsForValueParameter(
|
||||||
typeQualifierResolver,
|
typeQualifierResolver,
|
||||||
|
overriddenMembers,
|
||||||
// TODO: check me
|
// TODO: check me
|
||||||
parameterContainer = ownerFunction,
|
parameterContainer = ownerFunction,
|
||||||
methodContext = memberContext,
|
methodContext = memberContext,
|
||||||
@@ -229,6 +237,8 @@ class JavaClassEnhancementScope(
|
|||||||
|
|
||||||
private fun enhanceValueParameter(
|
private fun enhanceValueParameter(
|
||||||
ownerFunction: FirCallableMember,
|
ownerFunction: FirCallableMember,
|
||||||
|
overriddenMembers: List<FirCallableMember>,
|
||||||
|
hasReceiver: Boolean,
|
||||||
memberContext: FirJavaEnhancementContext,
|
memberContext: FirJavaEnhancementContext,
|
||||||
predefinedEnhancementInfo: PredefinedFunctionEnhancementInfo?,
|
predefinedEnhancementInfo: PredefinedFunctionEnhancementInfo?,
|
||||||
ownerParameter: FirJavaValueParameter,
|
ownerParameter: FirJavaValueParameter,
|
||||||
@@ -236,9 +246,10 @@ class JavaClassEnhancementScope(
|
|||||||
): EnhanceValueParameterResult {
|
): EnhanceValueParameterResult {
|
||||||
val signatureParts = ownerFunction.partsForValueParameter(
|
val signatureParts = ownerFunction.partsForValueParameter(
|
||||||
typeQualifierResolver,
|
typeQualifierResolver,
|
||||||
|
overriddenMembers,
|
||||||
parameterContainer = ownerParameter,
|
parameterContainer = ownerParameter,
|
||||||
methodContext = memberContext,
|
methodContext = memberContext,
|
||||||
typeInSignature = TypeInSignature.ValueParameter(index)
|
typeInSignature = TypeInSignature.ValueParameter(hasReceiver, index)
|
||||||
).enhance(session, jsr305State, predefinedEnhancementInfo?.parametersInfo?.getOrNull(index))
|
).enhance(session, jsr305State, predefinedEnhancementInfo?.parametersInfo?.getOrNull(index))
|
||||||
val firResolvedTypeRef = signatureParts.type
|
val firResolvedTypeRef = signatureParts.type
|
||||||
val defaultValue = ownerParameter.getDefaultValueFromAnnotation()
|
val defaultValue = ownerParameter.getDefaultValueFromAnnotation()
|
||||||
@@ -252,11 +263,13 @@ class JavaClassEnhancementScope(
|
|||||||
|
|
||||||
private fun enhanceReturnType(
|
private fun enhanceReturnType(
|
||||||
owner: FirCallableMember,
|
owner: FirCallableMember,
|
||||||
|
overriddenMembers: List<FirCallableMember>,
|
||||||
memberContext: FirJavaEnhancementContext,
|
memberContext: FirJavaEnhancementContext,
|
||||||
predefinedEnhancementInfo: PredefinedFunctionEnhancementInfo?
|
predefinedEnhancementInfo: PredefinedFunctionEnhancementInfo?
|
||||||
): FirResolvedTypeRef {
|
): FirResolvedTypeRef {
|
||||||
val signatureParts = owner.parts(
|
val signatureParts = owner.parts(
|
||||||
typeQualifierResolver,
|
typeQualifierResolver,
|
||||||
|
overriddenMembers,
|
||||||
typeContainer = owner, isCovariant = true,
|
typeContainer = owner, isCovariant = true,
|
||||||
containerContext = memberContext,
|
containerContext = memberContext,
|
||||||
containerApplicabilityType =
|
containerApplicabilityType =
|
||||||
@@ -297,22 +310,32 @@ class JavaClassEnhancementScope(
|
|||||||
}
|
}
|
||||||
|
|
||||||
object Receiver : TypeInSignature() {
|
object Receiver : TypeInSignature() {
|
||||||
override fun getTypeRef(member: FirCallableMember): FirTypeRef = member.receiverTypeRef!!
|
override fun getTypeRef(member: FirCallableMember): FirTypeRef {
|
||||||
|
if (member is FirJavaMethod) return member.valueParameters[0].returnTypeRef
|
||||||
|
return member.receiverTypeRef!!
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ValueParameter(val index: Int) : TypeInSignature() {
|
class ValueParameter(val hasReceiver: Boolean, val index: Int) : TypeInSignature() {
|
||||||
override fun getTypeRef(member: FirCallableMember): FirTypeRef = (member as FirFunction).valueParameters[index].returnTypeRef
|
override fun getTypeRef(member: FirCallableMember): FirTypeRef {
|
||||||
|
if (hasReceiver && member is FirJavaMethod) {
|
||||||
|
return (member as FirFunction).valueParameters[index + 1].returnTypeRef
|
||||||
|
}
|
||||||
|
return (member as FirFunction).valueParameters[index].returnTypeRef
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun FirCallableMember.partsForValueParameter(
|
private fun FirCallableMember.partsForValueParameter(
|
||||||
typeQualifierResolver: FirAnnotationTypeQualifierResolver,
|
typeQualifierResolver: FirAnnotationTypeQualifierResolver,
|
||||||
|
overriddenMembers: List<FirCallableMember>,
|
||||||
// TODO: investigate if it's really can be a null (check properties' with extension overrides in Java)
|
// TODO: investigate if it's really can be a null (check properties' with extension overrides in Java)
|
||||||
parameterContainer: FirAnnotationContainer?,
|
parameterContainer: FirAnnotationContainer?,
|
||||||
methodContext: FirJavaEnhancementContext,
|
methodContext: FirJavaEnhancementContext,
|
||||||
typeInSignature: TypeInSignature
|
typeInSignature: TypeInSignature
|
||||||
) = parts(
|
) = parts(
|
||||||
typeQualifierResolver,
|
typeQualifierResolver,
|
||||||
|
overriddenMembers,
|
||||||
parameterContainer, false,
|
parameterContainer, false,
|
||||||
parameterContainer?.let {
|
parameterContainer?.let {
|
||||||
methodContext.copyWithNewDefaultTypeQualifiers(typeQualifierResolver, jsr305State, it.annotations)
|
methodContext.copyWithNewDefaultTypeQualifiers(typeQualifierResolver, jsr305State, it.annotations)
|
||||||
@@ -323,6 +346,7 @@ class JavaClassEnhancementScope(
|
|||||||
|
|
||||||
private fun FirCallableMember.parts(
|
private fun FirCallableMember.parts(
|
||||||
typeQualifierResolver: FirAnnotationTypeQualifierResolver,
|
typeQualifierResolver: FirAnnotationTypeQualifierResolver,
|
||||||
|
overriddenMembers: List<FirCallableMember>,
|
||||||
typeContainer: FirAnnotationContainer?,
|
typeContainer: FirAnnotationContainer?,
|
||||||
isCovariant: Boolean,
|
isCovariant: Boolean,
|
||||||
containerContext: FirJavaEnhancementContext,
|
containerContext: FirJavaEnhancementContext,
|
||||||
@@ -334,7 +358,7 @@ class JavaClassEnhancementScope(
|
|||||||
typeQualifierResolver,
|
typeQualifierResolver,
|
||||||
typeContainer,
|
typeContainer,
|
||||||
typeRef as FirJavaTypeRef,
|
typeRef as FirJavaTypeRef,
|
||||||
this.overriddenMembers().map {
|
overriddenMembers.map {
|
||||||
typeInSignature.getTypeRef(it)
|
typeInSignature.getTypeRef(it)
|
||||||
},
|
},
|
||||||
isCovariant,
|
isCovariant,
|
||||||
|
|||||||
+18
-16
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.descriptors.Modality
|
|||||||
import org.jetbrains.kotlin.fir.FirSession
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirNamedFunction
|
import org.jetbrains.kotlin.fir.declarations.FirNamedFunction
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||||
|
import org.jetbrains.kotlin.fir.java.declarations.FirJavaMethod
|
||||||
import org.jetbrains.kotlin.fir.java.toNotNullConeKotlinType
|
import org.jetbrains.kotlin.fir.java.toNotNullConeKotlinType
|
||||||
import org.jetbrains.kotlin.fir.scopes.FirScope
|
import org.jetbrains.kotlin.fir.scopes.FirScope
|
||||||
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
|
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
|
||||||
@@ -54,29 +55,30 @@ class JavaClassUseSiteScope(
|
|||||||
private fun isEqualTypes(a: FirTypeRef, b: FirTypeRef) =
|
private fun isEqualTypes(a: FirTypeRef, b: FirTypeRef) =
|
||||||
isEqualTypes(a.toNotNullConeKotlinType(session), b.toNotNullConeKotlinType(session))
|
isEqualTypes(a.toNotNullConeKotlinType(session), b.toNotNullConeKotlinType(session))
|
||||||
|
|
||||||
private fun isOverriddenFunCheck(member: FirNamedFunction, self: FirNamedFunction): Boolean {
|
private fun isOverriddenFunCheck(overriddenInJava: FirJavaMethod, base: FirNamedFunction): Boolean {
|
||||||
return member.valueParameters.size == self.valueParameters.size &&
|
val receiverTypeRef = base.receiverTypeRef
|
||||||
member.valueParameters.zip(self.valueParameters).all { (memberParam, selfParam) ->
|
if (receiverTypeRef == null) {
|
||||||
isEqualTypes(memberParam.returnTypeRef, selfParam.returnTypeRef)
|
return overriddenInJava.valueParameters.size == base.valueParameters.size &&
|
||||||
}
|
overriddenInJava.valueParameters.zip(base.valueParameters).all { (memberParam, selfParam) ->
|
||||||
|
isEqualTypes(memberParam.returnTypeRef, selfParam.returnTypeRef)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (overriddenInJava.valueParameters.size != base.valueParameters.size + 1) return false
|
||||||
|
val baseParameterTypes = listOf(receiverTypeRef) + base.valueParameters.map { it.returnTypeRef }
|
||||||
|
val javaParameterTypes = overriddenInJava.valueParameters.map { it.returnTypeRef }
|
||||||
|
return baseParameterTypes.zip(javaParameterTypes).all { (baseType, typeFromJava) ->
|
||||||
|
isEqualTypes(baseType, typeFromJava)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun ConeFunctionSymbol.getOverridden(candidates: Set<ConeFunctionSymbol>): ConeCallableSymbol? {
|
internal fun ConeFunctionSymbol.getOverridden(candidates: Set<ConeFunctionSymbol>): ConeCallableSymbol? {
|
||||||
if (overriddenByBase.containsKey(this)) return overriddenByBase[this]
|
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 self = (this as FirFunctionSymbol).fir as FirNamedFunction
|
||||||
val overriding = candidates.firstOrNull {
|
val overriding = candidates.firstOrNull {
|
||||||
val member = (it as FirFunctionSymbol).fir as FirNamedFunction
|
val member = (it as FirFunctionSymbol).fir as FirJavaMethod
|
||||||
self.modality != Modality.FINAL
|
self.modality != Modality.FINAL && isOverriddenFunCheck(member, self)
|
||||||
&& sameReceivers(member.receiverTypeRef, self.receiverTypeRef)
|
|
||||||
&& isOverriddenFunCheck(member, self)
|
|
||||||
} // TODO: two or more overrides for one fun?
|
} // TODO: two or more overrides for one fun?
|
||||||
overriddenByBase[this] = overriding
|
overriddenByBase[this] = overriding
|
||||||
return overriding
|
return overriding
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
public open class Inheritor : R|Second| {
|
||||||
|
public open operator function foo R|First|.(first: R|kotlin/String|, s: R|kotlin/Int|): R|kotlin/Unit|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
interface First
|
||||||
|
|
||||||
|
open class Second {
|
||||||
|
open fun First.foo(s: String, i: Int) {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
FILE: Base.kt
|
||||||
|
public abstract interface First {
|
||||||
|
}
|
||||||
|
public open class Second {
|
||||||
|
public constructor(): super<R|kotlin/Any|>()
|
||||||
|
|
||||||
|
public open function foo R|First|.(s: R|kotlin/String|, i: R|kotlin/Int|): R|kotlin/Unit| {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
public class Inheritor extends Second {
|
||||||
|
public void foo(First first, String s, int i) {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
class Tester : Inheritor(), First {
|
||||||
|
fun test() {
|
||||||
|
foo("abc", 456)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
FILE: Test.kt
|
||||||
|
public final class Tester : R|Inheritor|, R|First| {
|
||||||
|
public constructor(): super<R|Inheritor|>()
|
||||||
|
|
||||||
|
public final function test(): R|kotlin/Unit| {
|
||||||
|
R|/Inheritor.foo|(String(abc), Int(456))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+5
@@ -64,6 +64,11 @@ public class FirMultiModuleResolveTestGenerated extends AbstractFirMultiModuleRe
|
|||||||
runTest("idea/testData/fir/multiModule/fullWithJavaPredefinedSignature/");
|
runTest("idea/testData/fir/multiModule/fullWithJavaPredefinedSignature/");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("javaInheritsKotlinExtension")
|
||||||
|
public void testJavaInheritsKotlinExtension() throws Exception {
|
||||||
|
runTest("idea/testData/fir/multiModule/javaInheritsKotlinExtension/");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("javaInheritsRawKotlin")
|
@TestMetadata("javaInheritsRawKotlin")
|
||||||
public void testJavaInheritsRawKotlin() throws Exception {
|
public void testJavaInheritsRawKotlin() throws Exception {
|
||||||
runTest("idea/testData/fir/multiModule/javaInheritsRawKotlin/");
|
runTest("idea/testData/fir/multiModule/javaInheritsRawKotlin/");
|
||||||
|
|||||||
Reference in New Issue
Block a user