diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/declarations/FirJavaMethod.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/declarations/FirJavaMethod.kt index 7ffd4bc1c43..d4089a48b0d 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/declarations/FirJavaMethod.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/declarations/FirJavaMethod.kt @@ -43,6 +43,9 @@ import org.jetbrains.kotlin.util.OperatorNameConventions.ITERATOR import org.jetbrains.kotlin.util.OperatorNameConventions.NEXT import org.jetbrains.kotlin.util.OperatorNameConventions.SET import org.jetbrains.kotlin.util.OperatorNameConventions.UNARY_OPERATION_NAMES +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract import kotlin.properties.Delegates @OptIn(FirImplementationDetail::class) @@ -227,3 +230,29 @@ class FirJavaMethodBuilder : FirFunctionBuilder, FirTypeParametersOwnerBuilder, inline fun buildJavaMethod(init: FirJavaMethodBuilder.() -> Unit): FirJavaMethod { return FirJavaMethodBuilder().apply(init).build() } + +@OptIn(ExperimentalContracts::class) +inline fun buildJavaMethodCopy(original: FirSimpleFunction, init: FirJavaMethodBuilder.() -> Unit): FirJavaMethod { + contract { + callsInPlace(init, InvocationKind.EXACTLY_ONCE) + } + val copyBuilder = FirJavaMethodBuilder() + copyBuilder.source = original.source + copyBuilder.session = original.session + copyBuilder.resolvePhase = original.resolvePhase + copyBuilder.attributes = original.attributes.copy() + copyBuilder.returnTypeRef = original.returnTypeRef + copyBuilder.valueParameters.addAll(original.valueParameters) + copyBuilder.body = original.body + copyBuilder.status = original.status + copyBuilder.dispatchReceiverType = original.dispatchReceiverType + copyBuilder.name = original.name + copyBuilder.symbol = original.symbol + copyBuilder.annotations.addAll(original.annotations) + copyBuilder.typeParameters.addAll(original.typeParameters) + val annotations = original.annotations + copyBuilder.annotationBuilder = { annotations } + return copyBuilder + .apply(init) + .build() +} diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/declarations/FirJavaValueParameter.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/declarations/FirJavaValueParameter.kt index bfef6f8fc9e..7653fe7f6be 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/declarations/FirJavaValueParameter.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/declarations/FirJavaValueParameter.kt @@ -20,6 +20,9 @@ import org.jetbrains.kotlin.fir.visitors.FirTransformer import org.jetbrains.kotlin.fir.visitors.FirVisitor import org.jetbrains.kotlin.fir.visitors.transformSingle import org.jetbrains.kotlin.name.Name +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract @OptIn(FirImplementationDetail::class) class FirJavaValueParameter @FirImplementationDetail constructor( @@ -174,3 +177,21 @@ class FirJavaValueParameterBuilder { inline fun buildJavaValueParameter(init: FirJavaValueParameterBuilder.() -> Unit): FirJavaValueParameter { return FirJavaValueParameterBuilder().apply(init).build() } + +@OptIn(ExperimentalContracts::class) +inline fun buildJavaValueParameterCopy(original: FirValueParameter, init: FirJavaValueParameterBuilder.() -> Unit): FirValueParameter { + contract { + callsInPlace(init, InvocationKind.EXACTLY_ONCE) + } + val copyBuilder = FirJavaValueParameterBuilder() + copyBuilder.source = original.source + copyBuilder.session = original.session + copyBuilder.attributes = original.attributes.copy() + copyBuilder.returnTypeRef = original.returnTypeRef + copyBuilder.name = original.name + val annotations = original.annotations + copyBuilder.annotationBuilder = { annotations } + copyBuilder.defaultValue = original.defaultValue + copyBuilder.isVararg = original.isVararg + return copyBuilder.apply(init).build() +} diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/SignatureEnhancement.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/SignatureEnhancement.kt index a3839b387b6..8df2a9d4d76 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/SignatureEnhancement.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/SignatureEnhancement.kt @@ -21,6 +21,7 @@ import org.jetbrains.kotlin.fir.declarations.synthetic.buildSyntheticProperty import org.jetbrains.kotlin.fir.initialSignatureAttr import org.jetbrains.kotlin.fir.java.JavaTypeParameterStack import org.jetbrains.kotlin.fir.java.declarations.* +import org.jetbrains.kotlin.fir.java.toConeKotlinTypeProbablyFlexible import org.jetbrains.kotlin.fir.render import org.jetbrains.kotlin.fir.scopes.jvm.computeJvmDescriptor import org.jetbrains.kotlin.fir.symbols.CallableId @@ -165,7 +166,10 @@ class FirSignatureEnhancement( val memberContext = context.copyWithNewDefaultTypeQualifiers(typeQualifierResolver, jsr305State, firMethod.annotations) val predefinedEnhancementInfo = - SignatureBuildingComponents.signature(owner.symbol.classId, firMethod.computeJvmDescriptor()).let { signature -> + SignatureBuildingComponents.signature( + owner.symbol.classId, + firMethod.computeJvmDescriptor { it.toConeKotlinTypeProbablyFlexible(session, javaTypeParameterStack) } + ).let { signature -> PREDEFINED_FUNCTION_ENHANCEMENT_INFO_BY_SIGNATURE[signature] } @@ -308,6 +312,9 @@ class FirSignatureEnhancement( ownerParameter: FirJavaValueParameter, index: Int ): FirResolvedTypeRef { + if (ownerParameter.returnTypeRef is FirResolvedTypeRef) { + return ownerParameter.returnTypeRef as FirResolvedTypeRef + } val signatureParts = ownerFunction.partsForValueParameter( typeQualifierResolver, overriddenMembers, diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/scopes/JavaClassMembersEnhancementScope.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/scopes/JavaClassMembersEnhancementScope.kt index fcedee9c6df..81db4df3827 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/scopes/JavaClassMembersEnhancementScope.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/scopes/JavaClassMembersEnhancementScope.kt @@ -5,31 +5,17 @@ package org.jetbrains.kotlin.fir.java.scopes -import org.jetbrains.kotlin.builtins.StandardNames -import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.declarations.FirCallableMemberDeclaration -import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin import org.jetbrains.kotlin.fir.declarations.FirProperty import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction import org.jetbrains.kotlin.fir.java.enhancement.FirSignatureEnhancement -import org.jetbrains.kotlin.fir.resolve.lookupSuperTypes import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.scopes.FirTypeScope import org.jetbrains.kotlin.fir.scopes.ProcessorAction -import org.jetbrains.kotlin.fir.scopes.impl.FirFakeOverrideGenerator -import org.jetbrains.kotlin.fir.scopes.jvm.computeJvmDescriptorReplacingKotlinToJava -import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag -import org.jetbrains.kotlin.fir.symbols.StandardClassIds import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.types.* -import org.jetbrains.kotlin.load.java.SpecialGenericSignatures -import org.jetbrains.kotlin.load.java.SpecialGenericSignatures.Companion.ERASED_COLLECTION_PARAMETER_SIGNATURES -import org.jetbrains.kotlin.load.java.SpecialGenericSignatures.Companion.ERASED_VALUE_PARAMETERS_SHORT_NAMES -import org.jetbrains.kotlin.load.java.SpecialGenericSignatures.Companion.ERASED_VALUE_PARAMETERS_SIGNATURES -import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.utils.addToStdlib.safeAs class JavaClassMembersEnhancementScope( session: FirSession, @@ -62,91 +48,10 @@ class JavaClassMembersEnhancementScope( return super.processPropertiesByName(name, processor) } - private fun FirSimpleFunction.changeSignatureIfErasedValueParameter(): FirSimpleFunction { - val typeParameters = owner.fir.typeParameters - if (typeParameters.isEmpty() || name !in ERASED_VALUE_PARAMETERS_SHORT_NAMES) { - return this - } - val jvmDescriptor = this.computeJvmDescriptorReplacingKotlinToJava().replace( - "kotlin/collections/Collection", - "java/util/Collection" - ) - if (ERASED_VALUE_PARAMETERS_SIGNATURES.none { it.endsWith(jvmDescriptor) }) { - return this - } - val superClassIds = listOfNotNull(symbol.callableId.classId) + - lookupSuperTypes(owner, lookupInterfaces = true, deep = true, useSiteSession = session).map { it.lookupTag.classId } - for (superClassId in superClassIds) { - val javaClassId = JavaToKotlinClassMap.mapKotlinToJava(superClassId.asSingleFqName().toUnsafe()) ?: superClassId - val newParameterTypes: List = when (val fqJvmDescriptor = "${javaClassId.asString()}.$jvmDescriptor") { - in ERASED_COLLECTION_PARAMETER_SIGNATURES -> { - valueParameters.map { - val typeParameter = typeParameters.first() - ConeClassLikeLookupTagImpl(ClassId.topLevel(StandardNames.FqNames.collection)).constructClassType( - arrayOf( - ConeTypeParameterLookupTag(typeParameter.symbol).constructType(emptyArray(), isNullable = false) - ), isNullable = false - ) - } - } - in ERASED_VALUE_PARAMETERS_SIGNATURES -> { - val specialSignatureInfo = SpecialGenericSignatures.getSpecialSignatureInfo(fqJvmDescriptor) - if (!specialSignatureInfo.isObjectReplacedWithTypeParameter) { - return this - } - valueParameters.mapIndexed { i, valueParameter -> - val classLikeType = - valueParameter.returnTypeRef.coneTypeSafe()?.lowerBoundIfFlexible().safeAs() - if (classLikeType?.lookupTag?.classId == StandardClassIds.Any) { - val typeParameterIndex = if (name.asString() == "containsValue") 1 else i - val typeParameter = typeParameters.getOrNull(typeParameterIndex) ?: typeParameters.first() - val type = ConeTypeParameterLookupTag(typeParameter.symbol).constructType( - emptyArray(), valueParameter.returnTypeRef.isMarkedNullable == true - ) - if (valueParameter.returnTypeRef.coneType is ConeFlexibleType) { - ConeFlexibleType( - type.withAttributes( - type.attributes.withFlexibleUnless { - it.hasEnhancedNullability - } - ), - type.withNullability(ConeNullability.NULLABLE) - ) - } else { - type - } - } else { - null - } - } - } - else -> { - continue - } - } - if (newParameterTypes.none { it != null }) { - return this - } - - return FirFakeOverrideGenerator.createCopyForFirFunction( - FirNamedFunctionSymbol(symbol.callableId), - this, - session, - FirDeclarationOrigin.Enhancement, - newParameterTypes = valueParameters.zip(newParameterTypes).map { (valueParameter, newType) -> - newType ?: valueParameter.returnTypeRef.coneType - }, - newDispatchReceiverType = dispatchReceiverType, - ) - - } - return this - } - override fun processFunctionsByName(name: Name, processor: (FirNamedFunctionSymbol) -> Unit) { useSiteMemberScope.processFunctionsByName(name) process@{ original -> val symbol = signatureEnhancement.enhancedFunction(original, name) - val enhancedFunction = (symbol.fir as? FirSimpleFunction)?.changeSignatureIfErasedValueParameter() + val enhancedFunction = (symbol.fir as? FirSimpleFunction) val enhancedFunctionSymbol = enhancedFunction?.symbol ?: symbol if (enhancedFunctionSymbol is FirNamedFunctionSymbol) { @@ -162,7 +67,6 @@ class JavaClassMembersEnhancementScope( private fun FirCallableMemberDeclaration<*>.overriddenMembers(name: Name): List> { val backMap = overrideBindCache.getOrPut(name) { - useSiteMemberScope.bindOverrides(name) useSiteMemberScope .overrideByBase .toList() diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/scopes/JavaClassUseSiteMemberScope.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/scopes/JavaClassUseSiteMemberScope.kt index 19d7470f1c5..5ad62bd582a 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/scopes/JavaClassUseSiteMemberScope.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/scopes/JavaClassUseSiteMemberScope.kt @@ -5,26 +5,30 @@ package org.jetbrains.kotlin.fir.java.scopes -import com.intellij.lang.jvm.types.JvmPrimitiveTypeKind -import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticProperty import org.jetbrains.kotlin.fir.declarations.synthetic.buildSyntheticProperty import org.jetbrains.kotlin.fir.java.declarations.* -import org.jetbrains.kotlin.fir.resolve.FirJavaSyntheticNamesProvider -import org.jetbrains.kotlin.fir.resolve.calls.syntheticNamesProvider -import org.jetbrains.kotlin.fir.scopes.FirScope -import org.jetbrains.kotlin.fir.scopes.FirTypeScope -import org.jetbrains.kotlin.fir.scopes.getContainingCallableNamesIfPresent -import org.jetbrains.kotlin.fir.scopes.getContainingClassifierNamesIfPresent +import org.jetbrains.kotlin.fir.java.toConeKotlinTypeProbablyFlexible +import org.jetbrains.kotlin.fir.resolve.toSymbol +import org.jetbrains.kotlin.fir.scopes.* import org.jetbrains.kotlin.fir.scopes.impl.AbstractFirUseSiteMemberScope +import org.jetbrains.kotlin.fir.scopes.jvm.computeJvmDescriptor +import org.jetbrains.kotlin.fir.scopes.jvm.computeJvmSignature import org.jetbrains.kotlin.fir.symbols.CallableId +import org.jetbrains.kotlin.fir.symbols.StandardClassIds import org.jetbrains.kotlin.fir.symbols.impl.* -import org.jetbrains.kotlin.fir.types.isUnit -import org.jetbrains.kotlin.fir.types.jvm.FirJavaTypeRef -import org.jetbrains.kotlin.load.java.structure.JavaPrimitiveType -import org.jetbrains.kotlin.load.java.structure.impl.JavaPrimitiveTypeImpl +import org.jetbrains.kotlin.fir.types.* +import org.jetbrains.kotlin.load.java.BuiltinSpecialProperties +import org.jetbrains.kotlin.load.java.JvmAbi +import org.jetbrains.kotlin.load.java.SpecialGenericSignatures +import org.jetbrains.kotlin.load.java.SpecialGenericSignatures.Companion.ERASED_COLLECTION_PARAMETER_NAMES +import org.jetbrains.kotlin.load.java.SpecialGenericSignatures.Companion.sameAsBuiltinMethodWithErasedValueParameters +import org.jetbrains.kotlin.load.java.getPropertyNamesCandidatesByAccessorName import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.types.AbstractTypeChecker +import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult class JavaClassUseSiteMemberScope( klass: FirJavaClass, @@ -37,15 +41,8 @@ class JavaClassUseSiteMemberScope( superTypesScope, declaredMemberScope ) { - internal fun bindOverrides(name: Name) { - val overrideCandidates = mutableSetOf() - declaredMemberScope.processFunctionsByName(name) { - overrideCandidates += it - } - superTypesScope.processFunctionsByName(name) { - it.getOverridden(overrideCandidates) - } - } + private val typeParameterStack = klass.javaTypeParameterStack + private val specialFunctions = hashMapOf>() override fun getCallableNames(): Set { return declaredMemberScope.getContainingCallableNamesIfPresent() + superTypesScope.getCallableNames() @@ -72,99 +69,378 @@ class JavaClassUseSiteMemberScope( }.symbol } - private fun processAccessorFunctionsAndPropertiesByName( - propertyName: Name, - getterNames: List, - processor: (FirVariableSymbol<*>) -> Unit - ) { - val overrideCandidates = mutableSetOf>() - declaredMemberScope.processPropertiesByName(propertyName) { variableSymbol -> - if (variableSymbol.isStatic) return@processPropertiesByName - overrideCandidates += variableSymbol + override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) { + val fields = mutableSetOf>() + val fieldNames = mutableSetOf() + + // fields + declaredMemberScope.processPropertiesByName(name) processor@{ variableSymbol -> + if (variableSymbol.isStatic) return@processor + fields += variableSymbol + fieldNames += variableSymbol.fir.name processor(variableSymbol) } - for (getterName in getterNames) { - var getterSymbol: FirNamedFunctionSymbol? = null - var setterSymbol: FirNamedFunctionSymbol? = null - declaredMemberScope.processFunctionsByName(getterName) { functionSymbol -> - if (getterSymbol == null) { - val function = functionSymbol.fir - if (!function.isStatic && function.valueParameters.isEmpty()) { - getterSymbol = functionSymbol - } - } - } - val setterName = session.syntheticNamesProvider.setterNameByGetterName(getterName) - if (getterSymbol != null && setterName != null) { - declaredMemberScope.processFunctionsByName(setterName) { functionSymbol -> - if (setterSymbol == null) { - val function = functionSymbol.fir - if (!function.isStatic && function.valueParameters.size == 1) { - val returnTypeRef = function.returnTypeRef - if (returnTypeRef.isUnit) { - // Unit return type - setterSymbol = functionSymbol - } else if (returnTypeRef is FirJavaTypeRef) { - // Void/void return type - when (val returnType = returnTypeRef.type) { - is JavaPrimitiveTypeImpl -> - if (returnType.psi.kind == JvmPrimitiveTypeKind.VOID) { - setterSymbol = functionSymbol - } - is JavaPrimitiveType -> - if (returnType.type == null) { - setterSymbol = functionSymbol - } - } - } - } - } - } - val accessorSymbol = generateAccessorSymbol(getterSymbol!!, setterSymbol, propertyName) - overrideCandidates += accessorSymbol - } - } + val fromSupertypes = superTypesScope.getProperties(name) - superTypesScope.processPropertiesByName(propertyName) { - when (val overriddenBy = it.getOverridden(overrideCandidates)) { - null -> processor(it) - is FirAccessorSymbol -> processor(overriddenBy) - is FirPropertySymbol -> if (it is FirPropertySymbol) { - directOverriddenProperties.getOrPut(overriddenBy) { mutableListOf() }.add(it) + for (propertyFromSupertype in fromSupertypes) { + if (propertyFromSupertype is FirFieldSymbol) { + if (propertyFromSupertype.fir.name !in fieldNames) { + processor(propertyFromSupertype) } + continue + } + if (propertyFromSupertype !is FirPropertySymbol) continue + val overrideInClass = propertyFromSupertype.createOverridePropertyIfExists(declaredMemberScope) + when { + overrideInClass != null -> { + directOverriddenProperties.getOrPut(overrideInClass) { mutableListOf() }.add(propertyFromSupertype) + overrideByBase[propertyFromSupertype] = overrideInClass + processor(overrideInClass) + } + else -> processor(propertyFromSupertype) } } } - override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) { - val getterNames = FirJavaSyntheticNamesProvider.possibleGetterNamesByPropertyName(name) - return processAccessorFunctionsAndPropertiesByName(name, getterNames, processor) + private fun FirVariableSymbol<*>.createOverridePropertyIfExists(scope: FirScope): FirPropertySymbol? { + if (this !is FirPropertySymbol || !doesClassOverridesProperty(this, scope)) return null + + val getterSymbol = this.findGetterOverride(scope)!! + val setterSymbol = + if (this.fir.isVar) + this.findSetterOverride(scope)!! + else + null + + return generateAccessorSymbol(getterSymbol, setterSymbol, fir.name) + } + + private fun doesClassOverridesProperty( + propertySymbolFromSupertype: FirPropertySymbol, + scope: FirScope, + ): Boolean { + val getter = propertySymbolFromSupertype.findGetterOverride(scope) + val setter = propertySymbolFromSupertype.findSetterOverride(scope) + + if (getter == null) return false + if (!propertySymbolFromSupertype.fir.isVar) return true + + return setter != null && setter.fir.modality == getter.fir.modality + } + + private fun FirPropertySymbol.findGetterOverride( + scope: FirScope, + ): FirNamedFunctionSymbol? { + val specialGetterName = getBuiltinSpecialPropertyGetterName() + if (specialGetterName != null) { + return findGetterByName(specialGetterName.asString(), scope) + } + + return findGetterByName(JvmAbi.getterName(fir.name.asString()), scope) + } + + private fun FirPropertySymbol.findGetterByName( + getterName: String, + scope: FirScope, + ): FirNamedFunctionSymbol? { + val propertyFromSupertype = fir + val expectedReturnType = propertyFromSupertype.returnTypeRef.coneTypeSafe() + return scope.getFunctions(Name.identifier(getterName)).firstNotNullResult factory@{ candidateSymbol -> + val candidate = candidateSymbol.fir + if (candidate.valueParameters.isNotEmpty()) return@factory null + + val candidateReturnType = candidate.returnTypeRef.toConeKotlinTypeProbablyFlexible(session, typeParameterStack) + + candidateSymbol.takeIf { + // TODO: Decide something for the case when property type is not computed yet + expectedReturnType == null || AbstractTypeChecker.isSubtypeOf(session.typeContext, candidateReturnType, expectedReturnType) + } + } + } + + private fun FirPropertySymbol.findSetterOverride( + scope: FirScope, + ): FirNamedFunctionSymbol? { + val propertyType = fir.returnTypeRef.coneTypeSafe() ?: return null + return scope.getFunctions(Name.identifier(JvmAbi.setterName(fir.name.asString()))).firstNotNullResult factory@{ candidateSymbol -> + val candidate = candidateSymbol.fir + if (candidate.valueParameters.size != 1) return@factory null + + if (!candidate.returnTypeRef.toConeKotlinTypeProbablyFlexible(session, typeParameterStack).isUnit) return@factory null + + val parameterType = + candidate.valueParameters.single().returnTypeRef.toConeKotlinTypeProbablyFlexible(session, typeParameterStack) + + candidateSymbol.takeIf { + AbstractTypeChecker.equalTypes(session.typeContext, parameterType, propertyType) + } + } + } + + private fun FirPropertySymbol.getBuiltinSpecialPropertyGetterName(): Name? { + var result: Name? = null + + superTypesScope.processOverriddenPropertiesAndSelf(this) { overridden -> + val fqName = overridden.fir.containingClass()?.classId?.asSingleFqName()?.child(overridden.fir.name) + + BuiltinSpecialProperties.PROPERTY_FQ_NAME_TO_JVM_GETTER_NAME_MAP[fqName]?.let { name -> + result = name + return@processOverriddenPropertiesAndSelf ProcessorAction.STOP + } + + ProcessorAction.NEXT + } + + return result } override fun processFunctionsByName(name: Name, processor: (FirNamedFunctionSymbol) -> Unit) { - val potentialPropertyNames = session.syntheticNamesProvider.possiblePropertyNamesByAccessorName(name) - val accessors = mutableListOf() - val getterName by lazy { session.syntheticNamesProvider.getterNameBySetterName(name) ?: name } - for (potentialPropertyName in potentialPropertyNames) { - processAccessorFunctionsAndPropertiesByName(potentialPropertyName, listOf(getterName)) { - if (it is FirAccessorSymbol) { - accessors += it - } - } - } - if (accessors.isEmpty()) { + val potentialPropertyNames = getPropertyNamesCandidatesByAccessorName(name) + + val renamedSpecialBuiltInNames = SpecialGenericSignatures.getBuiltinFunctionNamesByJvmName(name) + + if (potentialPropertyNames.isEmpty() && renamedSpecialBuiltInNames.isEmpty() && + !name.sameAsBuiltinMethodWithErasedValueParameters + ) { return super.processFunctionsByName(name, processor) } - super.processFunctionsByName(name) { functionSymbol -> - if (accessors.none { accessorSymbol -> - val syntheticProperty = accessorSymbol.fir as FirSyntheticProperty - syntheticProperty.getter.delegate === functionSymbol.fir || - syntheticProperty.setter?.delegate === functionSymbol.fir - } + + val overriddenProperties = potentialPropertyNames.flatMap(this::getProperties).filterIsInstance() + + specialFunctions.getOrPut(name) { + doProcessSpecialFunctions(name, overriddenProperties, renamedSpecialBuiltInNames) + }.forEach { + processor(it) + } + } + + private fun doProcessSpecialFunctions( + name: Name, + overriddenProperties: List, + renamedSpecialBuiltInNames: List + ): List { + val result = mutableListOf() + + declaredMemberScope.processFunctionsByName(name) { functionSymbol -> + if (functionSymbol.isStatic) return@processFunctionsByName + if (overriddenProperties.none { it.isOverriddenInClassBy(functionSymbol) } && + !functionSymbol.doesOverrideRenamedBuiltins(renamedSpecialBuiltInNames) && + !functionSymbol.shouldBeVisibleAsOverrideOfBuiltInWithErasedValueParameters() ) { - processor(functionSymbol) + result += functionSymbol + } + } + + addOverriddenSpecialMethods(name, result, declaredMemberScope) + + val overrideCandidates = result.toMutableSet() + + superTypesScope.processFunctionsByName(name) { + val overriddenBy = it.getOverridden(overrideCandidates) + if (overriddenBy == null) { + result += it + } + } + + return result + } + + private fun FirPropertySymbol.isOverriddenInClassBy(functionSymbol: FirNamedFunctionSymbol): Boolean { + val fir = fir as? FirSyntheticProperty ?: return false + + return fir.getter.delegate.symbol == functionSymbol || fir.setter?.delegate?.symbol == functionSymbol + } + + private fun addOverriddenSpecialMethods( + name: Name, + result: MutableList, + scope: FirScope, + ) { + superTypesScope.processFunctionsByName(name) { fromSupertype -> + obtainOverrideForBuiltinWithDifferentJvmName(fromSupertype, scope, name)?.let { + directOverriddenFunctions[it] = listOf(fromSupertype) + overrideByBase[fromSupertype] = it + result += it + } + + obtainOverrideForBuiltInWithErasedValueParametersInJava(fromSupertype, scope)?.let { + directOverriddenFunctions[it] = listOf(fromSupertype) + overrideByBase[fromSupertype] = it + result += it } } } + + private fun obtainOverrideForBuiltinWithDifferentJvmName( + symbol: FirNamedFunctionSymbol, + scope: FirScope, + name: Name, + ): FirNamedFunctionSymbol? { + val overriddenBuiltin = symbol.getOverriddenBuiltinWithDifferentJvmName() ?: return null + + val nameInJava = + SpecialGenericSignatures.SIGNATURE_TO_JVM_REPRESENTATION_NAME[overriddenBuiltin.fir.computeJvmSignature() ?: return null] + ?: return null + + for (candidateSymbol in scope.getFunctions(nameInJava)) { + val candidateFir = candidateSymbol.fir + val renamedCopy = buildJavaMethodCopy(candidateFir) { + this.name = name + this.symbol = FirNamedFunctionSymbol(CallableId(candidateFir.symbol.callableId.classId!!, name)) + }.apply { + initialSignatureAttr = candidateFir + } + + if (overrideChecker.isOverriddenFunction(renamedCopy, overriddenBuiltin.fir)) { + return renamedCopy.symbol + } + } + + return null + } + + private fun obtainOverrideForBuiltInWithErasedValueParametersInJava( + symbol: FirNamedFunctionSymbol, + scope: FirScope, + ): FirNamedFunctionSymbol? { + val overriddenBuiltin = + symbol.getOverriddenBuiltinFunctionWithErasedValueParametersInJava() + ?: return null + + return createOverrideForBuiltinFunctionWithErasedParameterIfNeeded(symbol, overriddenBuiltin, scope) + } + + private fun createOverrideForBuiltinFunctionWithErasedParameterIfNeeded( + fromSupertype: FirNamedFunctionSymbol, + overriddenBuiltin: FirNamedFunctionSymbol, + scope: FirScope, + ): FirNamedFunctionSymbol? { + return scope.getFunctions(overriddenBuiltin.fir.name).firstOrNull { candidateOverride -> + candidateOverride.fir.computeJvmDescriptor() == overriddenBuiltin.fir.computeJvmDescriptor() && + candidateOverride.hasErasedParameters() + }?.let { override -> + buildJavaMethodCopy(override.fir) { + this.valueParameters.clear() + override.fir.valueParameters.zip(fromSupertype.fir.valueParameters) + .mapTo(this.valueParameters) { (overrideParameter, parameterFromSupertype) -> + buildJavaValueParameterCopy(overrideParameter) { + this@buildJavaValueParameterCopy.returnTypeRef = parameterFromSupertype.returnTypeRef + } + } + + symbol = FirNamedFunctionSymbol(override.callableId) + }.apply { + initialSignatureAttr = override.fir + }.symbol + } + } + + // It's either overrides Collection.contains(Object) or Collection.containsAll(Collection) or similar methods + private fun FirNamedFunctionSymbol.hasErasedParameters(): Boolean { + val valueParameter = fir.valueParameters.first() + val parameterType = valueParameter.returnTypeRef.toConeKotlinTypeProbablyFlexible(session, typeParameterStack) + val upperBound = parameterType.upperBoundIfFlexible() + if (upperBound !is ConeClassLikeType) return false + + if (fir.name.asString() in ERASED_COLLECTION_PARAMETER_NAMES) { + require(upperBound.lookupTag.classId == StandardClassIds.Collection) { + "Unexpected type: ${upperBound.lookupTag.classId}" + } + + return upperBound.typeArguments.singleOrNull() is ConeStarProjection + } + + return upperBound.classId == StandardClassIds.Any + } + + private fun FirNamedFunctionSymbol.doesOverrideRenamedBuiltins(renamedSpecialBuiltInNames: List): Boolean { + return renamedSpecialBuiltInNames.any { + // e.g. 'removeAt' or 'toInt' + builtinName -> + val builtinSpecialFromSuperTypes = + getFunctionsFromSupertypes(builtinName).filter { it.getOverriddenBuiltinWithDifferentJvmName() != null } + if (builtinSpecialFromSuperTypes.isEmpty()) return@any false + + val currentJvmDescriptor = fir.computeJvmDescriptor(customName = builtinName.asString()) + + builtinSpecialFromSuperTypes.any { builtinSpecial -> + builtinSpecial.fir.computeJvmDescriptor() == currentJvmDescriptor + } + } + } + + private fun FirFunction<*>.computeJvmSignature(): String? { + return computeJvmSignature { it.toConeKotlinTypeProbablyFlexible(session, typeParameterStack) } + } + + private fun FirFunction<*>.computeJvmDescriptor(customName: String? = null, includeReturnType: Boolean = false): String { + return computeJvmDescriptor(customName, includeReturnType) { + it.toConeKotlinTypeProbablyFlexible( + session, + typeParameterStack + ) + } + } + + private fun getFunctionsFromSupertypes(name: Name): List { + val result = mutableListOf() + superTypesScope.processFunctionsByName(name) { + result += it + } + + return result + } + + private fun FirNamedFunctionSymbol.getOverriddenBuiltinWithDifferentJvmName(): FirNamedFunctionSymbol? { + var result: FirNamedFunctionSymbol? = null + + superTypesScope.processOverriddenFunctions(this) { + if (!it.isFromBuiltInClass(session)) return@processOverriddenFunctions ProcessorAction.NEXT + if (SpecialGenericSignatures.SIGNATURE_TO_JVM_REPRESENTATION_NAME.containsKey( + it.fir.computeJvmSignature() + ) + ) { + result = it + return@processOverriddenFunctions ProcessorAction.STOP + } + + ProcessorAction.NEXT + } + + return result + } + + private fun FirNamedFunctionSymbol.shouldBeVisibleAsOverrideOfBuiltInWithErasedValueParameters(): Boolean { + val name = fir.name + if (!name.sameAsBuiltinMethodWithErasedValueParameters) return false + val candidatesToOverride = + getFunctionsFromSupertypes(name).mapNotNull { + it.getOverriddenBuiltinFunctionWithErasedValueParametersInJava() + } + + val jvmDescriptor = fir.computeJvmDescriptor() + + return candidatesToOverride.any { candidate -> + candidate.fir.computeJvmDescriptor() == jvmDescriptor && this.hasErasedParameters() + } + } + + private fun FirNamedFunctionSymbol.getOverriddenBuiltinFunctionWithErasedValueParametersInJava(): FirNamedFunctionSymbol? { + var result: FirNamedFunctionSymbol? = null + + superTypesScope.processOverriddenFunctionsAndSelf(this) { + if (it.fir.computeJvmSignature() in SpecialGenericSignatures.ERASED_VALUE_PARAMETERS_SIGNATURES) { + result = it + return@processOverriddenFunctionsAndSelf ProcessorAction.STOP + } + + ProcessorAction.NEXT + } + + return result + } } + +private fun FirCallableSymbol<*>.isFromBuiltInClass(session: FirSession) = + dispatchReceiverClassOrNull()?.toSymbol(session)?.fir?.origin == FirDeclarationOrigin.BuiltIns diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/scopes/JavaOverrideChecker.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/scopes/JavaOverrideChecker.kt index d3dd4558737..0c451d1bfea 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/scopes/JavaOverrideChecker.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/scopes/JavaOverrideChecker.kt @@ -15,11 +15,9 @@ import org.jetbrains.kotlin.fir.resolve.fullyExpandedType import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap import org.jetbrains.kotlin.fir.scopes.impl.FirAbstractOverrideChecker -import org.jetbrains.kotlin.fir.scopes.jvm.computeJvmDescriptor import org.jetbrains.kotlin.fir.symbols.StandardClassIds import org.jetbrains.kotlin.fir.typeContext import org.jetbrains.kotlin.fir.types.* -import org.jetbrains.kotlin.load.java.SpecialGenericSignatures class JavaOverrideChecker internal constructor( private val session: FirSession, @@ -30,11 +28,10 @@ class JavaOverrideChecker internal constructor( private fun isEqualTypes( candidateType: ConeKotlinType, baseType: ConeKotlinType, - substitutor: ConeSubstitutor, - mayBeSpecialBuiltIn: Boolean + substitutor: ConeSubstitutor ): Boolean { - if (candidateType is ConeFlexibleType) return isEqualTypes(candidateType.lowerBound, baseType, substitutor, mayBeSpecialBuiltIn) - if (baseType is ConeFlexibleType) return isEqualTypes(candidateType, baseType.lowerBound, substitutor, mayBeSpecialBuiltIn) + if (candidateType is ConeFlexibleType) return isEqualTypes(candidateType.lowerBound, baseType, substitutor) + if (baseType is ConeFlexibleType) return isEqualTypes(candidateType, baseType.lowerBound, substitutor) if (candidateType is ConeClassLikeType && baseType is ConeClassLikeType) { val candidateTypeClassId = candidateType.fullyExpandedType(session).lookupTag.classId.let { it.readOnlyToMutable() ?: it } val baseTypeClassId = baseType.fullyExpandedType(session).lookupTag.classId.let { it.readOnlyToMutable() ?: it } @@ -49,22 +46,11 @@ class JavaOverrideChecker internal constructor( return isEqualArrayElementTypeProjections( candidateType.typeArguments.single(), baseType.typeArguments.single(), - substitutor, - mayBeSpecialBuiltIn + substitutor ) } return true } - // TODO: handle the situation in more proper way - // Typical case: class EnumMap implements Map - // We have containsKey(Object) in Map which is enhanced to containsKey(K) in supertype scope - // In EnumMap we have overridden containsKey(Object) which is not yet enhanced - // K may be substituted but after that we will get containsKey(Enum) from supertype, which still does not match... - if (mayBeSpecialBuiltIn && baseType is ConeTypeParameterType && - candidateType is ConeClassLikeType && candidateType.classId == StandardClassIds.Any - ) { - return true - } return with(context) { areEqualTypeConstructors( substitutor.substituteOrSelf(candidateType).typeConstructor(), @@ -76,25 +62,22 @@ class JavaOverrideChecker internal constructor( private fun isEqualTypes( candidateTypeRef: FirTypeRef, baseTypeRef: FirTypeRef, - substitutor: ConeSubstitutor, - mayBeSpecialBuiltIn: Boolean = false + substitutor: ConeSubstitutor ) = isEqualTypes( candidateTypeRef.toConeKotlinTypeProbablyFlexible(session, javaTypeParameterStack), baseTypeRef.toConeKotlinTypeProbablyFlexible(session, javaTypeParameterStack), - substitutor, - mayBeSpecialBuiltIn + substitutor ) private fun isEqualArrayElementTypeProjections( candidateTypeProjection: ConeTypeProjection, baseTypeProjection: ConeTypeProjection, - substitutor: ConeSubstitutor, - mayBeSpecialBuiltIn: Boolean + substitutor: ConeSubstitutor ): Boolean = when { candidateTypeProjection is ConeKotlinTypeProjection && baseTypeProjection is ConeKotlinTypeProjection -> candidateTypeProjection.kind == baseTypeProjection.kind && - isEqualTypes(candidateTypeProjection.type, baseTypeProjection.type, substitutor, mayBeSpecialBuiltIn) + isEqualTypes(candidateTypeProjection.type, baseTypeProjection.type, substitutor) candidateTypeProjection is ConeStarProjection && baseTypeProjection is ConeStarProjection -> true else -> false } @@ -169,13 +152,8 @@ class JavaOverrideChecker internal constructor( if (overrideCandidate.valueParameters.size != baseParameterTypes.size) return false val substitutor = buildTypeParametersSubstitutorIfCompatible(overrideCandidate, baseDeclaration) ?: return false - - val jvmDescriptor by lazy { baseDeclaration.computeJvmDescriptor() } - val mayBeSpecialBuiltIn = - baseDeclaration.name in SpecialGenericSignatures.ERASED_VALUE_PARAMETERS_SHORT_NAMES && - SpecialGenericSignatures.ERASED_VALUE_PARAMETERS_SIGNATURES.any { it.endsWith(jvmDescriptor) } return overrideCandidate.valueParameters.zip(baseParameterTypes).all { (paramFromJava, baseType) -> - isEqualTypes(paramFromJava.returnTypeRef, baseType, substitutor, mayBeSpecialBuiltIn) + isEqualTypes(paramFromJava.returnTypeRef, baseType, substitutor) } } diff --git a/compiler/fir/jvm/src/org/jetbrains/kotlin/fir/scopes/jvm/DescriptorUtils.kt b/compiler/fir/jvm/src/org/jetbrains/kotlin/fir/scopes/jvm/DescriptorUtils.kt index 3857ebc7a84..8509c3afd82 100644 --- a/compiler/fir/jvm/src/org/jetbrains/kotlin/fir/scopes/jvm/DescriptorUtils.kt +++ b/compiler/fir/jvm/src/org/jetbrains/kotlin/fir/scopes/jvm/DescriptorUtils.kt @@ -5,6 +5,9 @@ package org.jetbrains.kotlin.fir.scopes.jvm +import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap +import org.jetbrains.kotlin.fir.containingClass +import org.jetbrains.kotlin.fir.declarations.FirCallableMemberDeclaration import org.jetbrains.kotlin.fir.declarations.FirFunction import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction import org.jetbrains.kotlin.fir.symbols.StandardClassIds @@ -12,68 +15,44 @@ import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.impl.FirImplicitAnyTypeRef import org.jetbrains.kotlin.fir.types.impl.FirImplicitNullableAnyTypeRef import org.jetbrains.kotlin.fir.types.jvm.FirJavaTypeRef -import org.jetbrains.kotlin.load.java.structure.JavaClass -import org.jetbrains.kotlin.load.java.structure.JavaClassifierType import org.jetbrains.kotlin.load.java.structure.JavaPrimitiveType -import org.jetbrains.kotlin.load.java.structure.JavaTypeParameter +import org.jetbrains.kotlin.load.kotlin.SignatureBuildingComponents import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName -fun FirFunction<*>.computeJvmDescriptorReplacingKotlinToJava(): String = - computeJvmDescriptor() - .replace("kotlin/Any", "java/lang/Object") - .replace("kotlin/String", "java/lang/String") - .replace("kotlin/Throwable", "java/lang/Throwable") +fun FirFunction<*>.computeJvmSignature(typeConversion: (FirTypeRef) -> ConeKotlinType? = FirTypeRef::coneTypeSafe): String? { + if (this !is FirCallableMemberDeclaration<*>) return null + val containingClass = containingClass() ?: return null -fun FirFunction<*>.computeJvmDescriptor(): String = buildString { - if (this@computeJvmDescriptor is FirSimpleFunction) { - append(name.asString()) + return SignatureBuildingComponents.signature(containingClass.classId, computeJvmDescriptor(typeConversion = typeConversion)) +} + +fun FirFunction<*>.computeJvmDescriptor( + customName: String? = null, + includeReturnType: Boolean = true, + typeConversion: (FirTypeRef) -> ConeKotlinType? = FirTypeRef::coneTypeSafe +): String = buildString { + if (customName != null) { + append(customName) } else { - append("") + if (this@computeJvmDescriptor is FirSimpleFunction) { + append(name.asString()) + } else { + append("") + } } append("(") for (parameter in valueParameters) { - appendErasedType(parameter.returnTypeRef) + typeConversion(parameter.returnTypeRef)?.let(this::appendConeType) } append(")") - if (this@computeJvmDescriptor !is FirSimpleFunction || returnTypeRef.isVoid()) { - append("V") - } else { - appendErasedType(returnTypeRef) - } -} - -// TODO: primitive types, arrays, etc. -private fun StringBuilder.appendErasedType(typeRef: FirTypeRef) { - fun appendClass(klass: JavaClass) { - klass.fqName?.let { - append("L") - append(it.asString().replace(".", "/")) - append(";") - } - } - - when (typeRef) { - is FirResolvedTypeRef -> appendConeType(typeRef.type) - is FirJavaTypeRef -> { - when (val javaType = typeRef.type) { - is JavaClassifierType -> { - when (val classifier = javaType.classifier) { - is JavaClass -> appendClass(classifier) - is JavaTypeParameter -> { - val representative = classifier.upperBounds.firstOrNull { it.classifier is JavaClass } - if (representative == null) { - append("Ljava/lang/Object;") - } else { - appendClass(representative.classifier as JavaClass) - } - } - else -> return - } - } - } + if (includeReturnType) { + if (this@computeJvmDescriptor !is FirSimpleFunction || returnTypeRef.isVoid()) { + append("V") + } else { + typeConversion(returnTypeRef)?.let(this::appendConeType) } } } @@ -101,7 +80,8 @@ private fun StringBuilder.appendConeType(coneType: ConeKotlinType) { } fun appendClassLikeType(type: ConeClassLikeType) { - val classId = type.lookupTag.classId + val baseClassId = type.lookupTag.classId + val classId = JavaToKotlinClassMap.mapKotlinToJava(baseClassId.asSingleFqName().toUnsafe()) ?: baseClassId if (classId == StandardClassIds.Array) { append("[") type.typeArguments.forEach { typeArg -> diff --git a/compiler/fir/jvm/src/org/jetbrains/kotlin/fir/scopes/jvm/JvmMappedScope.kt b/compiler/fir/jvm/src/org/jetbrains/kotlin/fir/scopes/jvm/JvmMappedScope.kt index 62a08051b3c..cf7ed1b6c21 100644 --- a/compiler/fir/jvm/src/org/jetbrains/kotlin/fir/scopes/jvm/JvmMappedScope.kt +++ b/compiler/fir/jvm/src/org/jetbrains/kotlin/fir/scopes/jvm/JvmMappedScope.kt @@ -29,11 +29,11 @@ class JvmMappedScope( } val declaredSignatures by lazy { - declared.mapTo(mutableSetOf()) { it.fir.computeJvmDescriptorReplacingKotlinToJava() } + declared.mapTo(mutableSetOf()) { it.fir.computeJvmDescriptor() } } javaMappedClassUseSiteScope.processFunctionsByName(name) { symbol -> - val jvmSignature = symbol.fir.computeJvmDescriptorReplacingKotlinToJava() + val jvmSignature = symbol.fir.computeJvmDescriptor() if (jvmSignature in visibleMethods && jvmSignature !in declaredSignatures) { processor(symbol) } @@ -49,7 +49,7 @@ class JvmMappedScope( val hiddenConstructors = signatures.hiddenConstructors if (hiddenConstructors.isNotEmpty()) { javaMappedClassUseSiteScope.processDeclaredConstructors { symbol -> - val jvmSignature = symbol.fir.computeJvmDescriptorReplacingKotlinToJava() + val jvmSignature = symbol.fir.computeJvmDescriptor() if (jvmSignature !in hiddenConstructors) { processor(symbol) } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/AbstractFirUseSiteMemberScope.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/AbstractFirUseSiteMemberScope.kt index ca22a5f4dc1..e1c2e6d99f7 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/AbstractFirUseSiteMemberScope.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/AbstractFirUseSiteMemberScope.kt @@ -19,7 +19,7 @@ abstract class AbstractFirUseSiteMemberScope( ) : AbstractFirOverrideScope(session, overrideChecker) { private val functions = hashMapOf>() - private val directOverriddenFunctions = hashMapOf>() + protected val directOverriddenFunctions = hashMapOf>() protected val directOverriddenProperties = hashMapOf>() override fun processFunctionsByName(name: Name, processor: (FirNamedFunctionSymbol) -> Unit) { diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/scopes/FirScope.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/scopes/FirScope.kt index 835b8d15e63..ca1d6e293c1 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/scopes/FirScope.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/scopes/FirScope.kt @@ -61,6 +61,15 @@ fun FirTypeScope.processOverriddenFunctionsAndSelf( return processOverriddenFunctions(functionSymbol, processor) } +fun FirTypeScope.processOverriddenPropertiesAndSelf( + propertySymbol: FirPropertySymbol, + processor: (FirPropertySymbol) -> ProcessorAction +): ProcessorAction { + if (!processor(propertySymbol)) return ProcessorAction.STOP + + return processOverriddenProperties(propertySymbol, processor) +} + enum class ProcessorAction { STOP, NEXT, diff --git a/compiler/testData/diagnostics/tests/j+k/collectionOverrides/collectionStringImpl.fir.kt b/compiler/testData/diagnostics/tests/j+k/collectionOverrides/collectionStringImpl.fir.kt new file mode 100644 index 00000000000..6dcb7e4ed52 --- /dev/null +++ b/compiler/testData/diagnostics/tests/j+k/collectionOverrides/collectionStringImpl.fir.kt @@ -0,0 +1,85 @@ +// FILE: CollectionStringImpl.java + +import java.util.Collection; +import java.util.Iterator; + +public class CollectionStringImpl implements Collection { + @Override + public int size() { + return 0; + } + + @Override + public boolean isEmpty() { + return false; + } + + @Override + public boolean contains(Object o) { + return false; + } + + + @Override + public Iterator iterator() { + return null; + } + + + @Override + public Object[] toArray() { + return new Object[0]; + } + + + @Override + public T[] toArray(T[] a) { + return null; + } + + @Override + public boolean add(String s) { + return false; + } + + @Override + public boolean remove(Object o) { + return false; + } + + @Override + public boolean containsAll(Collection c) { + return false; + } + + @Override + public boolean addAll(Collection c) { + return false; + } + + @Override + public boolean removeAll(Collection c) { + return false; + } + + @Override + public boolean retainAll(Collection c) { + return false; + } + + @Override + public void clear() { + + } + + public boolean contains(String o) { + return true; + } +} + +// FILE: main.kt + +fun test(x: CollectionStringImpl) { + x.contains("") + (x as Collection).contains("") +} diff --git a/compiler/testData/diagnostics/tests/j+k/collectionOverrides/collectionStringImpl.kt b/compiler/testData/diagnostics/tests/j+k/collectionOverrides/collectionStringImpl.kt index 13e04293af0..08b86b53d45 100644 --- a/compiler/testData/diagnostics/tests/j+k/collectionOverrides/collectionStringImpl.kt +++ b/compiler/testData/diagnostics/tests/j+k/collectionOverrides/collectionStringImpl.kt @@ -1,4 +1,3 @@ -// FIR_IDENTICAL // FILE: CollectionStringImpl.java import java.util.Collection; diff --git a/compiler/testData/diagnostics/tests/j+k/collectionOverrides/contains.fir.kt b/compiler/testData/diagnostics/tests/j+k/collectionOverrides/contains.fir.kt index 00249856f38..574fa9177aa 100644 --- a/compiler/testData/diagnostics/tests/j+k/collectionOverrides/contains.fir.kt +++ b/compiler/testData/diagnostics/tests/j+k/collectionOverrides/contains.fir.kt @@ -40,14 +40,14 @@ fun foo( 1 in a b.contains("") - b.contains(1) + b.contains(1) "" in b - 1 in b + 1 in b ic.contains("") - ic.contains(1) + ic.contains(1) "" in ic - 1 in ic + 1 in ic ka.contains("") ka.contains(1) @@ -55,9 +55,9 @@ fun foo( 1 in ka kb.contains("") - kb.contains(1) + kb.contains(1) "" in kb - 1 in kb + 1 in kb al.contains("") al.contains(1) diff --git a/compiler/testData/diagnostics/tests/j+k/collectionOverrides/containsAll.fir.kt b/compiler/testData/diagnostics/tests/j+k/collectionOverrides/containsAll.fir.kt index 7b3f6352e90..6d8492519a4 100644 --- a/compiler/testData/diagnostics/tests/j+k/collectionOverrides/containsAll.fir.kt +++ b/compiler/testData/diagnostics/tests/j+k/collectionOverrides/containsAll.fir.kt @@ -40,16 +40,16 @@ fun foo( a.containsAll(ca) b.containsAll(cs) - b.containsAll(ca) + b.containsAll(ca) ic.containsAll(cs) - ic.containsAll(ca) + ic.containsAll(ca) ka.containsAll(cs) ka.containsAll(ca) kb.containsAll(cs) - kb.containsAll(ca) + kb.containsAll(ca) al.containsAll(cs) al.containsAll(ca) diff --git a/compiler/testData/diagnostics/tests/j+k/collectionOverrides/containsAndOverload.fir.kt b/compiler/testData/diagnostics/tests/j+k/collectionOverrides/containsAndOverload.fir.kt index 14ba0abc693..71d078632c4 100644 --- a/compiler/testData/diagnostics/tests/j+k/collectionOverrides/containsAndOverload.fir.kt +++ b/compiler/testData/diagnostics/tests/j+k/collectionOverrides/containsAndOverload.fir.kt @@ -12,13 +12,13 @@ abstract class KA : A() { } fun foo(a: A, ka: KA) { - a.contains("") - a.contains(1) - "" in a - 1 in a + a.contains("") + a.contains(1) + "" in a + 1 in a ka.contains("") - ka.contains(1) + ka.contains(1) "" in ka - 1 in ka + 1 in ka } diff --git a/compiler/testData/diagnostics/tests/j+k/collectionOverrides/irrelevantMapGetAbstract.fir.kt b/compiler/testData/diagnostics/tests/j+k/collectionOverrides/irrelevantMapGetAbstract.fir.kt new file mode 100644 index 00000000000..055a7d36daf --- /dev/null +++ b/compiler/testData/diagnostics/tests/j+k/collectionOverrides/irrelevantMapGetAbstract.fir.kt @@ -0,0 +1,19 @@ +// FILE: Dict.java + +public abstract class Dict { + abstract public V get(Object key); +} + +// FILE: MHashtable.java + +abstract public class MHashtable extends Dict implements java.util.Map { + public V get(Object key) { return null; } +} + +// FILE: main.kt + +abstract class C1 : MHashtable() + +abstract class C2 : MHashtable() { + override fun get(key: String) = 1 +} diff --git a/compiler/testData/diagnostics/tests/j+k/collectionOverrides/irrelevantMapGetAbstract.kt b/compiler/testData/diagnostics/tests/j+k/collectionOverrides/irrelevantMapGetAbstract.kt index 586d232e4f4..409e6ed8c49 100644 --- a/compiler/testData/diagnostics/tests/j+k/collectionOverrides/irrelevantMapGetAbstract.kt +++ b/compiler/testData/diagnostics/tests/j+k/collectionOverrides/irrelevantMapGetAbstract.kt @@ -1,4 +1,3 @@ -// FIR_IDENTICAL // FILE: Dict.java public abstract class Dict { diff --git a/compiler/testData/diagnostics/tests/j+k/collectionOverrides/removeAtInt.fir.kt b/compiler/testData/diagnostics/tests/j+k/collectionOverrides/removeAtInt.fir.kt deleted file mode 100644 index f57ecfdb76a..00000000000 --- a/compiler/testData/diagnostics/tests/j+k/collectionOverrides/removeAtInt.fir.kt +++ /dev/null @@ -1,32 +0,0 @@ -// JAVAC_EXPECTED_FILE -// FILE: A.java -abstract public class A extends B { - public Integer removeAt(int x) { } - public boolean remove(Integer x) { } -} - -// FILE: main.kt -import java.util.*; - -abstract class B : MutableList, AbstractList() { - override fun removeAt(index: Int): Int = null!! - override fun remove(element: Int): Boolean = null!! -} - -abstract class D : AbstractList() { - // removeAt() doesn't exist in java/util/AbstractList, it's a - // fake override of the method from kotlin/collections/MutableList - override fun removeAt(index: Int): Int = null!! - // AbstractList::remove() should return Int here. No fake overrides created. - // This may be a bug because the old compiler doesn't report a diagnostic here. - override fun remove(element: Int): Boolean = null!! -} - -fun main(a: A, b: B, c: ArrayList) { - a.remove(1) - a.removeAt(0) - b.remove(1) - b.removeAt(0) - c.remove(1) - c.removeAt(0) -} diff --git a/compiler/testData/diagnostics/tests/j+k/collectionOverrides/removeAtInt.kt b/compiler/testData/diagnostics/tests/j+k/collectionOverrides/removeAtInt.kt index 8510bc01ac0..581138898ae 100644 --- a/compiler/testData/diagnostics/tests/j+k/collectionOverrides/removeAtInt.kt +++ b/compiler/testData/diagnostics/tests/j+k/collectionOverrides/removeAtInt.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // JAVAC_EXPECTED_FILE // FILE: A.java abstract public class A extends B { diff --git a/compiler/testData/diagnostics/tests/j+k/finalCollectionSize.fir.kt b/compiler/testData/diagnostics/tests/j+k/finalCollectionSize.fir.kt deleted file mode 100644 index 8eba11c0bc3..00000000000 --- a/compiler/testData/diagnostics/tests/j+k/finalCollectionSize.fir.kt +++ /dev/null @@ -1,12 +0,0 @@ -// JAVAC_EXPECTED_FILE -// FILE: A.java - -abstract public class A extends java.util.ArrayList { - public final int size() { return 0; } -} - -// FILE: main.kt - -class B : A() { - override val size: Int = 1 -} diff --git a/compiler/testData/diagnostics/tests/j+k/finalCollectionSize.kt b/compiler/testData/diagnostics/tests/j+k/finalCollectionSize.kt index fc53d7be086..2b918487101 100644 --- a/compiler/testData/diagnostics/tests/j+k/finalCollectionSize.kt +++ b/compiler/testData/diagnostics/tests/j+k/finalCollectionSize.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // JAVAC_EXPECTED_FILE // FILE: A.java diff --git a/compiler/testData/diagnostics/tests/j+k/primitiveOverrides/specializedMap.fir.kt b/compiler/testData/diagnostics/tests/j+k/primitiveOverrides/specializedMap.fir.kt new file mode 100644 index 00000000000..2bfe4e906af --- /dev/null +++ b/compiler/testData/diagnostics/tests/j+k/primitiveOverrides/specializedMap.fir.kt @@ -0,0 +1,113 @@ +// FILE: AbstractSpecializedMap.java +public abstract class AbstractSpecializedMap implements java.util.Map { + public abstract double put(int x, double y); + public abstract double remove(int k); + public abstract double get(int k); + + public abstract boolean containsKey(int k); + public boolean containsKey(Object x) { + return false; + } + + public abstract boolean containsValue(double v); + public boolean containsValue(Object x) { + return false; + } +} + +// FILE: SpecializedMap.java +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; +import java.util.Map; +import java.util.Set; + +public class SpecializedMap extends AbstractSpecializedMap { + public double put(int x, double y) { + return 123.0; + } + + @Override + public Double get(Object key) { + return null; + } + + @Override + public Double put(Integer key, Double value) { + return null; + } + + public double remove(int k) { + return 456.0; + } + + + public Double remove(Object ok) { + return null; + } + + + public double get(int k) { + return 789.0; + } + + public boolean containsKey(int k) { + return true; + } + + public boolean containsValue(double v) { + return true; + } + + @Override + public void putAll(Map m) { + } + + @Override + public void clear() { + + } + + @NotNull + @Override + public Set keySet() { + return null; + } + + @NotNull + @Override + public Collection values() { + return null; + } + + @NotNull + @Override + public Set> entrySet() { + return null; + } + + @Override + public int size() { + return 0; + } + + @Override + public boolean isEmpty() { + return false; + } +} + +// FILE: main.kt +fun foo(x: SpecializedMap) { + x.containsKey(1) + x.containsKey(null) + + x.get(2) + x.get(null) + + x.remove(3) + x.remove(null) + + x.put(4, 5.0) + x.put(4, null) +} diff --git a/compiler/testData/diagnostics/tests/j+k/primitiveOverrides/specializedMap.kt b/compiler/testData/diagnostics/tests/j+k/primitiveOverrides/specializedMap.kt index f26f5d83449..1aaaa82660d 100644 --- a/compiler/testData/diagnostics/tests/j+k/primitiveOverrides/specializedMap.kt +++ b/compiler/testData/diagnostics/tests/j+k/primitiveOverrides/specializedMap.kt @@ -1,4 +1,3 @@ -// FIR_IDENTICAL // FILE: AbstractSpecializedMap.java public abstract class AbstractSpecializedMap implements java.util.Map { public abstract double put(int x, double y); diff --git a/compiler/testData/loadJava/compiledJava/modality/ModalityOfFakeOverrides.fir.txt b/compiler/testData/loadJava/compiledJava/modality/ModalityOfFakeOverrides.fir.txt index a3f0016c51b..b5baee9257a 100644 --- a/compiler/testData/loadJava/compiledJava/modality/ModalityOfFakeOverrides.fir.txt +++ b/compiler/testData/loadJava/compiledJava/modality/ModalityOfFakeOverrides.fir.txt @@ -1,8 +1,6 @@ public open class ModalityOfFakeOverrides : R|java/util/AbstractList!>| { @R|java/lang/Override|() @R|org/jetbrains/annotations/NotNull|() public open operator fun get(index: R|kotlin/Int|): R|@EnhancedNullability kotlin/String| - @R|java/lang/Override|() public open fun size(): R|kotlin/Int| - public constructor(): R|test/ModalityOfFakeOverrides| } diff --git a/idea/idea-frontend-fir/testData/memberScopeByFqName/java.lang.String.txt b/idea/idea-frontend-fir/testData/memberScopeByFqName/java.lang.String.txt index 0e037893735..5ac4a2205df 100644 --- a/idea/idea-frontend-fir/testData/memberScopeByFqName/java.lang.String.txt +++ b/idea/idea-frontend-fir/testData/memberScopeByFqName/java.lang.String.txt @@ -52,46 +52,25 @@ KtFirJavaFieldSymbol: symbolKind: MEMBER visibility: PRIVATE -KtFirFunctionSymbol: +KtFirSyntheticJavaPropertySymbol: annotatedType: [] kotlin/Int annotationClassIds: [] annotations: [] callableIdIfNonLocal: java.lang.String.length dispatchType: java/lang/String - isExtension: false - isExternal: false - isInline: false - isOperator: false - isOverride: false - isSuspend: false - modality: OPEN - name: length - origin: JAVA - receiverType: null - symbolKind: MEMBER - typeParameters: [] - valueParameters: [] - visibility: PUBLIC - -KtFirKotlinPropertySymbol: - annotatedType: [] kotlin/Int - annotationClassIds: [] - annotations: [] - callableIdIfNonLocal: kotlin.CharSequence.length - dispatchType: kotlin/CharSequence getter: KtFirPropertyGetterSymbol() - hasBackingField: false + hasBackingField: true hasGetter: true hasSetter: false initializer: null - isConst: false isExtension: false - isLateInit: false isOverride: false isVal: true - modality: ABSTRACT + javaGetterName: length + javaSetterName: null + modality: OPEN name: length - origin: LIBRARY + origin: JAVA_SYNTHETIC_PROPERTY receiverType: null setter: null symbolKind: MEMBER