diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/scopes/JavaClassEnhancementScope.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/scopes/JavaClassEnhancementScope.kt index 8c23eed25d8..418712f4c3b 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/scopes/JavaClassEnhancementScope.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/scopes/JavaClassEnhancementScope.kt @@ -19,9 +19,11 @@ import org.jetbrains.kotlin.fir.java.enhancement.* import org.jetbrains.kotlin.fir.java.enhancement.EnhancementSignatureParts import org.jetbrains.kotlin.fir.java.toNotNullConeKotlinType import org.jetbrains.kotlin.fir.java.types.FirJavaTypeRef +import org.jetbrains.kotlin.fir.render import org.jetbrains.kotlin.fir.scopes.FirScope import org.jetbrains.kotlin.fir.scopes.ProcessorAction import org.jetbrains.kotlin.fir.symbols.* +import org.jetbrains.kotlin.fir.symbols.impl.FirAccessorSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol import org.jetbrains.kotlin.fir.types.* @@ -74,30 +76,43 @@ class JavaClassEnhancementScope( private fun enhance( original: ConeVariableSymbol, name: Name - ): FirPropertySymbol { - val firField = (original as FirBasedSymbol<*>).fir as? FirJavaField ?: error("Can't make enhancement for $original") + ): ConePropertySymbol { + when (val firElement = (original as FirBasedSymbol<*>).fir) { + is FirJavaField -> { - val memberContext = context.copyWithNewDefaultTypeQualifiers(typeQualifierResolver, jsr305State, firField.annotations) - val newReturnTypeRef = enhanceReturnType(firField, emptyList(), memberContext, null) + val memberContext = context.copyWithNewDefaultTypeQualifiers(typeQualifierResolver, jsr305State, firElement.annotations) + val newReturnTypeRef = enhanceReturnType(firElement, emptyList(), memberContext, null) - val symbol = FirPropertySymbol(original.callableId) - with(firField) { - FirMemberPropertyImpl( - this@JavaClassEnhancementScope.session, null, symbol, name, - visibility, modality, isExpect, isActual, isOverride, - isConst = false, isLateInit = false, - receiverTypeRef = null, - returnTypeRef = newReturnTypeRef, - isVar = isVar, initializer = null, - getter = FirDefaultPropertyGetter(this@JavaClassEnhancementScope.session, null, newReturnTypeRef, visibility), - setter = FirDefaultPropertySetter(this@JavaClassEnhancementScope.session, null, newReturnTypeRef, visibility), - delegate = null - ).apply { - annotations += firField.annotations - status.isStatic = firField.isStatic + val symbol = FirPropertySymbol(original.callableId) + with(firElement) { + FirMemberPropertyImpl( + this@JavaClassEnhancementScope.session, null, symbol, name, + visibility, modality, isExpect, isActual, isOverride, + isConst = false, isLateInit = false, + receiverTypeRef = null, + returnTypeRef = newReturnTypeRef, + isVar = isVar, initializer = null, + getter = FirDefaultPropertyGetter(this@JavaClassEnhancementScope.session, null, newReturnTypeRef, visibility), + setter = FirDefaultPropertySetter(this@JavaClassEnhancementScope.session, null, newReturnTypeRef, visibility), + delegate = null + ).apply { + annotations += firElement.annotations + status.isStatic = firElement.isStatic + } + } + return symbol + } + is FirJavaMethod -> { + original as FirAccessorSymbol + return enhanceMethod( + firElement, original.accessorId, original.accessorId.callableName, isAccessor = true, propertyId = original.callableId + ) as FirAccessorSymbol + } + else -> { + if (original is ConePropertySymbol) return original + error("Can't make enhancement for $original: `${firElement.render()}`") } } - return symbol } private fun enhance( @@ -107,7 +122,17 @@ class JavaClassEnhancementScope( val firMethod = (original as FirFunctionSymbol).fir as? FirFunction if (firMethod !is FirJavaMethod && firMethod !is FirJavaConstructor || firMethod !is FirCallableMemberDeclaration) return original + return enhanceMethod(firMethod, original.callableId, name) as FirFunctionSymbol + } + private fun enhanceMethod( + firMethod: FirFunction, + methodId: CallableId, + name: Name, + isAccessor: Boolean = false, + propertyId: CallableId? = null + ): ConeCallableSymbol { + require(firMethod is FirCallableMemberDeclaration) val memberContext = context.copyWithNewDefaultTypeQualifiers(typeQualifierResolver, jsr305State, firMethod.annotations) val predefinedEnhancementInfo = @@ -144,7 +169,7 @@ class JavaClassEnhancementScope( ) } - val symbol = FirFunctionSymbol(original.callableId) + val symbol = if (!isAccessor) FirFunctionSymbol(methodId) else FirAccessorSymbol(callableId = propertyId!!, accessorId = methodId) FirMemberFunctionImpl( this@JavaClassEnhancementScope.session, null, symbol, name, newReceiverTypeRef, newReturnTypeRef @@ -250,8 +275,7 @@ class JavaClassEnhancementScope( typeInSignature = TypeInSignature.ValueParameter(hasReceiver, index) ).enhance(session, jsr305State, predefinedEnhancementInfo?.parametersInfo?.getOrNull(index)) val firResolvedTypeRef = signatureParts.type - val defaultValue = ownerParameter.getDefaultValueFromAnnotation() - val defaultValueExpression = when (defaultValue) { + val defaultValueExpression = when (val defaultValue = ownerParameter.getDefaultValueFromAnnotation()) { NullDefaultValue -> FirConstExpressionImpl(session, null, IrConstKind.Null, null) is StringDefaultValue -> firResolvedTypeRef.type.lexicalCastFrom(session, defaultValue.value) null -> null diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/scopes/JavaClassUseSiteScope.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/scopes/JavaClassUseSiteScope.kt index a3a73e23799..890129df57e 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/scopes/JavaClassUseSiteScope.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/scopes/JavaClassUseSiteScope.kt @@ -8,17 +8,21 @@ package org.jetbrains.kotlin.fir.java.scopes import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.declarations.FirCallableMemberDeclaration import org.jetbrains.kotlin.fir.declarations.FirNamedFunction +import org.jetbrains.kotlin.fir.declarations.FirProperty import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.java.toNotNullConeKotlinType -import org.jetbrains.kotlin.fir.resolve.transformers.firUnsafe 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.symbols.ConeCallableSymbol import org.jetbrains.kotlin.fir.symbols.ConeFunctionSymbol import org.jetbrains.kotlin.fir.symbols.ConeVariableSymbol +import org.jetbrains.kotlin.fir.symbols.* +import org.jetbrains.kotlin.fir.symbols.impl.FirAccessorSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol import org.jetbrains.kotlin.fir.typeContext import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.name.Name @@ -32,7 +36,7 @@ class JavaClassUseSiteScope( internal val symbol = klass.symbol //base symbol as key, overridden as value - private val overriddenByBase = mutableMapOf() + private val overriddenByBase = mutableMapOf() private val context: ConeTypeContext = session.typeContext @@ -71,14 +75,46 @@ class JavaClassUseSiteScope( } } - internal fun ConeFunctionSymbol.getOverridden(candidates: Set): ConeCallableSymbol? { + private fun isOverriddenPropertyCheck(overriddenInJava: FirNamedFunction, base: FirProperty): Boolean { + val receiverTypeRef = base.receiverTypeRef + if (receiverTypeRef == null) { + // TODO: setters + return overriddenInJava.valueParameters.isEmpty() + } else { + if (overriddenInJava.valueParameters.size != 1) return false + return isEqualTypes(receiverTypeRef, overriddenInJava.valueParameters.single().returnTypeRef) + } + } + + internal fun ConeCallableSymbol.getOverridden(candidates: Set): ConeCallableSymbol? { if (overriddenByBase.containsKey(this)) return overriddenByBase[this] - val self = (this as FirFunctionSymbol).fir as FirNamedFunction - val overriding = candidates.firstOrNull { - val member = (it as FirFunctionSymbol).firUnsafe() - self.modality != Modality.FINAL && isOverriddenFunCheck(member, self) - } // TODO: two or more overrides for one fun? + val overriding = when (this) { + is FirFunctionSymbol -> { + val self = fir as FirNamedFunction + candidates.firstOrNull { + val member = (it as FirFunctionSymbol).fir as FirNamedFunction + self.modality != Modality.FINAL && isOverriddenFunCheck(member, self) + } + } + is FirPropertySymbol -> { + val self = fir as FirProperty + candidates.firstOrNull { + val member = (it as FirFunctionSymbol).fir as FirNamedFunction + self.modality != Modality.FINAL && isOverriddenPropertyCheck(member, self) + + } + } + is FirAccessorSymbol -> { + val self = fir as FirNamedFunction + candidates.firstOrNull { + val member = (it as FirFunctionSymbol).fir as FirNamedFunction + self.modality != Modality.FINAL && isOverriddenFunCheck(member, self) + } + } + else -> error("Unexpected callable symbol: $this") + } + // TODO: two or more overrides for one fun? overriddenByBase[this] = overriding return overriding } @@ -102,14 +138,51 @@ class JavaClassUseSiteScope( } } + private fun processAccessorFunctionsByName( + propertyName: Name, + accessorName: Name, + processor: (ConePropertySymbol) -> ProcessorAction + ): ProcessorAction { + val overrideCandidates = mutableSetOf() + if (!declaredMemberScope.processFunctionsByName(accessorName) { functionSymbol -> + overrideCandidates += functionSymbol + val accessorSymbol = FirAccessorSymbol( + accessorId = functionSymbol.callableId, + callableId = CallableId(functionSymbol.callableId.packageName, functionSymbol.callableId.className, propertyName) + ) + if (functionSymbol is FirBasedSymbol<*>) { + (functionSymbol.fir as? FirCallableMemberDeclaration)?.let { callableMember -> accessorSymbol.bind(callableMember) } + } + processor(accessorSymbol) + } + ) return ProcessorAction.STOP + + return superTypesScope.processPropertiesByName(propertyName) { + val firCallableMember = (it as FirBasedSymbol<*>).fir as? FirCallableMemberDeclaration + if (firCallableMember?.isStatic == true) { + ProcessorAction.NEXT + } else { + val overriddenBy = it.getOverridden(overrideCandidates) + if (overriddenBy == null && it is ConePropertySymbol) { + processor(it) + } else { + ProcessorAction.NEXT + } + } + } + } + override fun processPropertiesByName(name: Name, processor: (ConeVariableSymbol) -> ProcessorAction): ProcessorAction { - val seen = mutableSetOf() if (!declaredMemberScope.processPropertiesByName(name) { - seen += it processor(it) } ) return ProcessorAction.STOP - return ProcessorAction.NEXT + val getterName = Name.identifier(getterPrefix + name.asString().capitalize()) + return processAccessorFunctionsByName(name, getterName, processor) + } + + companion object { + private const val getterPrefix = "get" } } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirLocalScope.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirLocalScope.kt index f89ef8cc223..00ada5e0e0c 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirLocalScope.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirLocalScope.kt @@ -12,6 +12,7 @@ import org.jetbrains.kotlin.fir.scopes.FirScope import org.jetbrains.kotlin.fir.scopes.ProcessorAction import org.jetbrains.kotlin.fir.symbols.ConeFunctionSymbol import org.jetbrains.kotlin.fir.symbols.ConeVariableSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol import org.jetbrains.kotlin.name.Name class FirLocalScope : FirScope { @@ -22,7 +23,7 @@ class FirLocalScope : FirScope { fun storeDeclaration(declaration: FirNamedDeclaration) { when (declaration) { is FirVariable -> properties[declaration.name] = declaration.symbol - is FirNamedFunction -> functions[declaration.name] = declaration.symbol + is FirNamedFunction -> functions[declaration.name] = declaration.symbol as FirFunctionSymbol } } diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/FirNamedFunction.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/FirNamedFunction.kt index 05e11a16193..c562927e3ab 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/FirNamedFunction.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/FirNamedFunction.kt @@ -27,8 +27,6 @@ interface FirNamedFunction : @VisitedSupertype FirFunction, FirCallableMemberDec override val isOverride: Boolean get() = status.isOverride - override val symbol: FirFunctionSymbol - override fun accept(visitor: FirVisitor, data: D): R = visitor.visitNamedFunction(this, data) diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/impl/FirMemberFunctionImpl.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/impl/FirMemberFunctionImpl.kt index d6827e8b7ed..336aa46453b 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/impl/FirMemberFunctionImpl.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/impl/FirMemberFunctionImpl.kt @@ -10,11 +10,9 @@ import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.FirSession -import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration -import org.jetbrains.kotlin.fir.declarations.FirNamedFunction -import org.jetbrains.kotlin.fir.declarations.FirValueParameter +import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.expressions.FirBlock -import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol import org.jetbrains.kotlin.fir.transformInplace import org.jetbrains.kotlin.fir.transformSingle @@ -24,12 +22,12 @@ import org.jetbrains.kotlin.name.Name open class FirMemberFunctionImpl : FirAbstractCallableMember, FirNamedFunction, FirModifiableFunction { - override val symbol: FirFunctionSymbol + override val symbol: FirCallableSymbol constructor( session: FirSession, psi: PsiElement?, - symbol: FirFunctionSymbol, + symbol: FirCallableSymbol, name: Name, receiverTypeRef: FirTypeRef?, returnTypeRef: FirTypeRef diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirAccessorSymbol.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirAccessorSymbol.kt new file mode 100644 index 00000000000..f33b923e5d8 --- /dev/null +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirAccessorSymbol.kt @@ -0,0 +1,14 @@ +/* + * 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.symbols.impl + +import org.jetbrains.kotlin.fir.symbols.CallableId +import org.jetbrains.kotlin.fir.symbols.ConePropertySymbol + +class FirAccessorSymbol( + override val callableId: CallableId, + val accessorId: CallableId +) : ConePropertySymbol, FirCallableSymbol() \ No newline at end of file diff --git a/compiler/testData/ir/irText/expressions/javaSyntheticPropertyAccess.fir.txt b/compiler/testData/ir/irText/expressions/javaSyntheticPropertyAccess.fir.txt index cf7ca3fd1e9..db78dc8fe43 100644 --- a/compiler/testData/ir/irText/expressions/javaSyntheticPropertyAccess.fir.txt +++ b/compiler/testData/ir/irText/expressions/javaSyntheticPropertyAccess.fir.txt @@ -2,10 +2,10 @@ FILE fqName: fileName:/javaSyntheticPropertyAccess.kt FUN name:test visibility:public modality:FINAL <> (j:.J) returnType:kotlin.Unit VALUE_PARAMETER name:j index:0 type:.J BLOCK_BODY - ERROR_CALL 'No getter found for R|/J.foo|' type=kotlin.Int - ERROR_CALL 'Unresolved reference: R|/J.foo|' type=IrErrorType - VAR name: type:kotlin.Int [val] - ERROR_CALL 'No getter found for R|/J.foo|' type=kotlin.Int - ERROR_CALL 'Unresolved reference: R|/J.foo|' type=IrErrorType - GET_VAR 'val : kotlin.Int [val] declared in .test' type=kotlin.Int origin=null - ERROR_CALL 'Unresolved reference: R|/J.foo|' type=IrErrorType + ERROR_CALL 'Unresolved reference: #' type=IrErrorType + ERROR_CALL 'Unresolved reference: #' type=IrErrorType + VAR name: type:IrErrorType [val] + ERROR_CALL 'Unresolved reference: #' type=IrErrorType + ERROR_CALL 'Unresolved reference: #' type=IrErrorType + GET_VAR 'val : IrErrorType [val] declared in .test' type=IrErrorType origin=null + ERROR_CALL 'Unresolved reference: #' type=IrErrorType diff --git a/compiler/testData/loadJava/compiledJava/PackageLocalVisibility.fir.txt b/compiler/testData/loadJava/compiledJava/PackageLocalVisibility.fir.txt index 36961e14b1f..d1fecd75217 100644 --- a/compiler/testData/loadJava/compiledJava/PackageLocalVisibility.fir.txt +++ b/compiler/testData/loadJava/compiledJava/PackageLocalVisibility.fir.txt @@ -9,6 +9,10 @@ public open class JFrame : R|awt/Frame| { protected/*protected and package*/ get(): R|ft|! protected/*protected and package*/ set(value: R|ft|!): kotlin/Unit + public/*package*/ open var accessibleContext: R|ft|! + public/*package*/ get(): R|ft|! + public/*package*/ set(value: R|ft|!): kotlin/Unit + public final fun JFrame(): R|test/JFrame| } diff --git a/idea/testData/fir/multiModule/javaInheritsKotlinProperty/extraDump.java.txt b/idea/testData/fir/multiModule/javaInheritsKotlinProperty/extraDump.java.txt new file mode 100644 index 00000000000..159b27052d7 --- /dev/null +++ b/idea/testData/fir/multiModule/javaInheritsKotlinProperty/extraDump.java.txt @@ -0,0 +1,4 @@ +public open class Inheritor : R|java/lang/Object|, R|Base| { + public open operator fun getX(): R|kotlin/Int| + +} diff --git a/idea/testData/fir/multiModule/javaInheritsKotlinProperty/jvm/Base.kt b/idea/testData/fir/multiModule/javaInheritsKotlinProperty/jvm/Base.kt new file mode 100644 index 00000000000..b59589c78de --- /dev/null +++ b/idea/testData/fir/multiModule/javaInheritsKotlinProperty/jvm/Base.kt @@ -0,0 +1,3 @@ +interface Base { + val x: Int +} \ No newline at end of file diff --git a/idea/testData/fir/multiModule/javaInheritsKotlinProperty/jvm/Base.txt b/idea/testData/fir/multiModule/javaInheritsKotlinProperty/jvm/Base.txt new file mode 100644 index 00000000000..ff77fe4f514 --- /dev/null +++ b/idea/testData/fir/multiModule/javaInheritsKotlinProperty/jvm/Base.txt @@ -0,0 +1,6 @@ +FILE: Base.kt + public abstract interface Base : R|kotlin/Any| { + public abstract val x: R|kotlin/Int| + public get(): R|kotlin/Int| + + } diff --git a/idea/testData/fir/multiModule/javaInheritsKotlinProperty/jvm/Inheritor.java b/idea/testData/fir/multiModule/javaInheritsKotlinProperty/jvm/Inheritor.java new file mode 100644 index 00000000000..8e448f8145d --- /dev/null +++ b/idea/testData/fir/multiModule/javaInheritsKotlinProperty/jvm/Inheritor.java @@ -0,0 +1,5 @@ +public class Inheritor implements Base { + public int getX() { + return 42; + } +} \ No newline at end of file diff --git a/idea/testData/fir/multiModule/javaInheritsKotlinProperty/jvm/Test.kt b/idea/testData/fir/multiModule/javaInheritsKotlinProperty/jvm/Test.kt new file mode 100644 index 00000000000..5e9391a3761 --- /dev/null +++ b/idea/testData/fir/multiModule/javaInheritsKotlinProperty/jvm/Test.kt @@ -0,0 +1,5 @@ +class Tester : Inheritor() { + fun test(): Int { + return x + } +} \ No newline at end of file diff --git a/idea/testData/fir/multiModule/javaInheritsKotlinProperty/jvm/Test.txt b/idea/testData/fir/multiModule/javaInheritsKotlinProperty/jvm/Test.txt new file mode 100644 index 00000000000..a64cae97643 --- /dev/null +++ b/idea/testData/fir/multiModule/javaInheritsKotlinProperty/jvm/Test.txt @@ -0,0 +1,11 @@ +FILE: Test.kt + public final class Tester : R|Inheritor| { + public constructor(): R|Tester| { + super() + } + + public final fun test(): R|kotlin/Int| { + ^test R|/Inheritor.x| + } + + } diff --git a/idea/tests/org/jetbrains/kotlin/idea/fir/FirMultiModuleResolveTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/fir/FirMultiModuleResolveTestGenerated.java index 4f7c3e31a95..c33dbf15efb 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/fir/FirMultiModuleResolveTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/fir/FirMultiModuleResolveTestGenerated.java @@ -69,6 +69,11 @@ public class FirMultiModuleResolveTestGenerated extends AbstractFirMultiModuleRe runTest("idea/testData/fir/multiModule/javaInheritsKotlinExtension/"); } + @TestMetadata("javaInheritsKotlinProperty") + public void testJavaInheritsKotlinProperty() throws Exception { + runTest("idea/testData/fir/multiModule/javaInheritsKotlinProperty/"); + } + @TestMetadata("javaInheritsRawKotlin") public void testJavaInheritsRawKotlin() throws Exception { runTest("idea/testData/fir/multiModule/javaInheritsRawKotlin/");