Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.java.scopes
import org.jetbrains.kotlin.KtFakeSourceElementKind
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fakeElement
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.analysis.checkers.isVisibleInClass
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.builder.buildSimpleFunctionCopy
import org.jetbrains.kotlin.fir.declarations.impl.FirDeclarationStatusImpl
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyGetter
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertySetter
import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticProperty
import org.jetbrains.kotlin.fir.declarations.synthetic.buildSyntheticProperty
import org.jetbrains.kotlin.fir.declarations.utils.*
import org.jetbrains.kotlin.fir.java.SyntheticPropertiesCacheKey
import org.jetbrains.kotlin.fir.java.declarations.FirJavaClass
import org.jetbrains.kotlin.fir.java.declarations.FirJavaMethod
import org.jetbrains.kotlin.fir.java.declarations.buildJavaMethodCopy
import org.jetbrains.kotlin.fir.java.declarations.buildJavaValueParameterCopy
import org.jetbrains.kotlin.fir.java.resolveIfJavaType
import org.jetbrains.kotlin.fir.java.symbols.FirJavaOverriddenSyntheticPropertySymbol
import org.jetbrains.kotlin.fir.java.syntheticPropertiesStorage
import org.jetbrains.kotlin.fir.java.toConeKotlinTypeProbablyFlexible
import org.jetbrains.kotlin.fir.resolve.defaultType
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.impl.FirTypeIntersectionScopeContext.ResultOfIntersection
import org.jetbrains.kotlin.fir.scopes.impl.MembersByScope
import org.jetbrains.kotlin.fir.scopes.impl.isIntersectionOverride
import org.jetbrains.kotlin.fir.scopes.impl.similarFunctionsOrBothProperties
import org.jetbrains.kotlin.fir.scopes.jvm.computeJvmDescriptor
import org.jetbrains.kotlin.fir.scopes.jvm.computeJvmDescriptorRepresentation
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
import org.jetbrains.kotlin.load.java.*
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.SpecialGenericSignatures.Companion.sameAsRenamedInJvmBuiltin
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.StandardClassIds
import org.jetbrains.kotlin.name.withClassId
import org.jetbrains.kotlin.types.AbstractTypeChecker
import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty
import org.jetbrains.kotlin.utils.addToStdlib.runIf
/**
* It's a kind of use-site scope specialized for a Java owner class. Provides access to symbols by names, both for
* declared inside Java-class and inherited from its base classes (as usual for use-site scopes).
*
* * all functions that are explicitly declared in a Java class, are visible by default.
* Exceptions: functions that have corresponding properties; functions that override renamed builtins (e.g. charAt);
* functions that are overrides with erased type parameters (e.g. contains(Object)).
* See [isVisibleInCurrentClass]. E.g. contains(String) or get(int) are visible as explicitly declared functions.
*
* * also, this scope as a use-site member scope shows us some functions from supertypes. Here we have two choices (see [collectFunctions]):
* * in the fast path, which is used when supertypes do not include any suspend functions AND the name is "standard"
* (we don't suspect possible builtin renaming or type parameter erasing), we use a standard procedure:
* class sees all supertype functions except those overridden by explicitly declared functions in the class
* * otherwise, [processSpecialFunctions] comes into play.
* It attempts to find a specific override for this "erased type parameter" and "renamed built-in" case.
* In case of success, it always creates a synthetic function and shows it as a scope part:
* * in case we have an "accidental normal override", like contains(String) or get(int),
* its "hidden" version is created as the synthetic function
* * in case we don't have it, we create an implicit function with such a signature (contains(String), get(int)) as the synthetic function
*/
class JavaClassUseSiteMemberScope(
private val klass: FirJavaClass,
session: FirSession,
superTypeScopes: List,
declaredMemberScope: FirContainingNamesAwareScope
) : AbstractFirUseSiteMemberScope(
klass.symbol.toLookupTag(),
session,
JavaOverrideChecker(session, klass.javaTypeParameterStack, superTypeScopes, considerReturnTypeKinds = true),
overrideCheckerForIntersection = null,
superTypeScopes,
klass.defaultType(),
declaredMemberScope
) {
private val typeParameterStack = klass.javaTypeParameterStack
private val canUseSpecialGetters: Boolean by lazy { !klass.hasKotlinSuper(session) }
private val javaOverrideChecker: JavaOverrideChecker get() = overrideChecker as JavaOverrideChecker
private val syntheticPropertyCache = session.syntheticPropertiesStorage.cacheByOwner.getValue(klass, null)
private fun generateSyntheticPropertySymbol(
getterSymbol: FirNamedFunctionSymbol,
setterSymbol: FirNamedFunctionSymbol?,
property: FirProperty,
takeModalityFromGetter: Boolean,
): FirSyntheticPropertySymbol {
val callableId = getterSymbol.callableId.withClassId(klass.classId)
return buildSyntheticProperty {
moduleData = session.moduleData
name = property.name
symbol = FirJavaOverriddenSyntheticPropertySymbol(
getterId = callableId,
propertyId = CallableId(klass.classId, property.name)
)
delegateGetter = getterSymbol.fir
delegateSetter = setterSymbol?.fir
status = getterSymbol.fir.status.copy(
modality = if (takeModalityFromGetter) {
delegateGetter.modality ?: property.modality
} else {
chooseModalityForAccessor(property, delegateGetter)
}
)
deprecationsProvider = getDeprecationsProviderFromAccessors(session, delegateGetter, delegateSetter)
dispatchReceiverType = klass.defaultType()
}.symbol
}
private fun chooseModalityForAccessor(property: FirProperty, getter: FirSimpleFunction): Modality? {
val a = property.modality
val b = getter.modality
if (a == null) return b
if (b == null) return a
return minOf(a, b)
}
override fun collectProperties(name: Name): Collection> {
val fields = mutableSetOf>()
val fieldNames = mutableSetOf()
val result = mutableSetOf>()
// fields
declaredMemberScope.processPropertiesByName(name) processor@{ variableSymbol ->
if (variableSymbol.isStatic) return@processor
fields += variableSymbol
fieldNames += variableSymbol.fir.name
result += variableSymbol
}
/*
* From supertype we can get:
* 1. Set of properties with same name (including regular and extension properties)
* 2. Field from some java superclass (only one, if class have more than one superclass then we can choose
* just one field because this is incorrect code anyway)
*/
val fromSupertypes = supertypeScopeContext.collectIntersectionResultsForCallables(name, FirScope::processPropertiesByName)
val (fieldsFromSupertype, propertiesFromSupertypes) = fromSupertypes.partition {
it is ResultOfIntersection.SingleMember && it.chosenSymbol is FirFieldSymbol
}
assert(fieldsFromSupertype.size in 0..1)
fieldsFromSupertype.firstOrNull()?.chosenSymbol?.let { fieldSymbol ->
require(fieldSymbol is FirFieldSymbol)
if (fieldSymbol.name !in fieldNames) {
result.add(fieldSymbol)
}
}
@Suppress("UNCHECKED_CAST")
for (overriddenProperty in propertiesFromSupertypes as List>) {
val key = SyntheticPropertiesCacheKey(
name,
overriddenProperty.chosenSymbol.receiverParameter?.typeRef?.coneType,
overriddenProperty.chosenSymbol.resolvedContextReceivers.ifNotEmpty { map { it.typeRef.coneType } } ?: emptyList()
)
val overrideInClass = syntheticPropertyCache.getValue(key, this to overriddenProperty)
val chosenSymbol = overrideInClass ?: overriddenProperty.chosenSymbol
directOverriddenProperties[chosenSymbol] = listOf(overriddenProperty)
overriddenProperty.overriddenMembers.forEach { overrideByBase[it.member] = overrideInClass }
result += chosenSymbol
}
return result
}
internal fun syntheticPropertyFromOverride(overriddenProperty: ResultOfIntersection): FirSyntheticPropertySymbol? {
val overrideInClass = overriddenProperty.overriddenMembers.firstNotNullOfOrNull superMember@{ (symbol, baseScope) ->
// We may call this function at the STATUS phase, which means that using resolved status may lead to cycle
// So we need to use raw status here
if (!symbol.isVisibleInClass(klass.symbol, symbol.rawStatus)) return@superMember null
symbol.createOverridePropertyIfExists(declaredMemberScope, takeModalityFromGetter = true)
?: superTypeScopes.firstNotNullOfOrNull superScope@{ scope ->
if (scope == baseScope) return@superScope null
symbol.createOverridePropertyIfExists(scope, takeModalityFromGetter = false)
}
}
return overrideInClass
}
private fun FirPropertySymbol.createOverridePropertyIfExists(
scope: FirScope,
takeModalityFromGetter: Boolean
): FirSyntheticPropertySymbol? {
val getterSymbol = this.findGetterOverride(scope) ?: return null
val setterSymbol =
if (this.fir.isVar)
this.findSetterOverride(scope) ?: return null
else
null
if (setterSymbol != null && setterSymbol.fir.modality != getterSymbol.fir.modality) return null
return generateSyntheticPropertySymbol(getterSymbol, setterSymbol, fir, takeModalityFromGetter)
}
private fun FirPropertySymbol.findGetterOverride(
scope: FirScope,
): FirNamedFunctionSymbol? {
val specialGetterName = if (canUseSpecialGetters) getBuiltinSpecialPropertyGetterName() else null
val name = specialGetterName?.asString() ?: JvmAbi.getterName(fir.name.asString())
return findGetterOverride(name, scope)
}
private fun FirPropertySymbol.findGetterOverride(
getterName: String,
scope: FirScope,
): FirNamedFunctionSymbol? {
val propertyFromSupertype = fir
val expectedReturnType = propertyFromSupertype.returnTypeRef.coneTypeSafe()
val receiverCount = (if (receiverParameter != null) 1 else 0) + resolvedContextReceivers.size
return scope.getFunctions(Name.identifier(getterName)).firstNotNullOfOrNull factory@{ candidateSymbol ->
val candidate = candidateSymbol.fir
if (candidate.valueParameters.size != receiverCount) return@factory null
if (!checkValueParameters(candidate)) return@factory null
val candidateReturnType = candidate.returnTypeRef.toConeKotlinTypeProbablyFlexible(
session, typeParameterStack, source?.fakeElement(KtFakeSourceElementKind.Enhancement)
)
candidateSymbol.takeIf {
when {
candidate.isAcceptableAsAccessorOverride() ->
// TODO: Decide something for the case when property type is not computed yet
expectedReturnType == null ||
AbstractTypeChecker.isSubtypeOf(session.typeContext, candidateReturnType, expectedReturnType)
else -> false
}
}
}
}
private fun FirPropertySymbol.findSetterOverride(
scope: FirScope,
): FirNamedFunctionSymbol? {
val propertyType = fir.returnTypeRef.coneTypeSafe() ?: return null
val receiverCount = (if (receiverParameter != null) 1 else 0) + resolvedContextReceivers.size
return scope.getFunctions(Name.identifier(JvmAbi.setterName(fir.name.asString()))).firstNotNullOfOrNull factory@{ candidateSymbol ->
val candidate = candidateSymbol.fir
if (candidate.valueParameters.size != receiverCount + 1) return@factory null
if (!checkValueParameters(candidate)) return@factory null
val fakeSource = source?.fakeElement(KtFakeSourceElementKind.Enhancement)
if (!candidate.returnTypeRef.toConeKotlinTypeProbablyFlexible(session, typeParameterStack, fakeSource).isUnit) {
return@factory null
}
val parameterType =
candidate.valueParameters.last().returnTypeRef.toConeKotlinTypeProbablyFlexible(session, typeParameterStack, fakeSource)
candidateSymbol.takeIf {
candidate.isAcceptableAsAccessorOverride() && AbstractTypeChecker.equalTypes(
session.typeContext, parameterType, propertyType
)
}
}
}
private fun FirPropertySymbol.checkValueParameters(candidate: FirSimpleFunction): Boolean {
var parameterIndex = 0
val fakeSource = source?.fakeElement(KtFakeSourceElementKind.Enhancement)
for (contextReceiver in this.resolvedContextReceivers) {
if (contextReceiver.typeRef.coneType.computeJvmDescriptorRepresentation() !=
candidate.valueParameters[parameterIndex++].returnTypeRef
.toConeKotlinTypeProbablyFlexible(session, typeParameterStack, fakeSource)
.computeJvmDescriptorRepresentation()
) {
return false
}
}
return receiverParameter == null ||
receiverParameter!!.typeRef.coneType.computeJvmDescriptorRepresentation() ==
candidate.valueParameters[parameterIndex].returnTypeRef
.toConeKotlinTypeProbablyFlexible(session, typeParameterStack, fakeSource)
.computeJvmDescriptorRepresentation()
}
private fun FirSimpleFunction.isAcceptableAsAccessorOverride(): Boolean {
// We don't accept here accessors with type parameters from Kotlin to avoid strange cases like KT-59038
// However, we (temporarily, see below) accept accessors from Kotlin in general to keep K1 compatibility in cases like KT-59550
// KT-59601: we are going to forbid accessors from Kotlin in general after some investigation and/or deprecation period
return isJavaOrEnhancement || typeParameters.isEmpty()
}
private fun FirPropertySymbol.getBuiltinSpecialPropertyGetterName(): Name? {
var result: Name? = null
superTypeScopes.processOverriddenPropertiesAndSelf(this) { overridden ->
val fqName = overridden.fir.containingClassLookupTag()?.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 FirNamedFunctionSymbol.isVisibleInCurrentClass(): Boolean {
val potentialPropertyNames = getPropertyNamesCandidatesByAccessorName(name)
val hasCorrespondingProperty = potentialPropertyNames.any { propertyName ->
getProperties(propertyName).any l@{ propertySymbol ->
// TODO: add magic overrides from LazyJavaClassMemberScope.isVisibleAsFunctionInCurrentClass
if (propertySymbol !is FirPropertySymbol) return@l false
// We may call this function at the STATUS phase, which means that using resolved status may lead to cycle
// so we need to use raw status here
propertySymbol.isVisibleInClass([email protected], propertySymbol.rawStatus) &&
propertySymbol.isOverriddenInClassBy(this)
}
}
if (hasCorrespondingProperty) return false
return !doesOverrideRenamedBuiltins() &&
!shouldBeVisibleAsOverrideOfBuiltInWithErasedValueParameters()
}
private fun FirNamedFunctionSymbol.doesOverrideRenamedBuiltins(): Boolean {
// e.g. 'removeAt' or 'toInt'
val builtinName = SpecialGenericSignatures.getBuiltinFunctionNamesByJvmName(name) ?: return false
val builtinSpecialFromSuperTypes = supertypeScopeContext.collectMembersGroupedByScope(builtinName, FirScope::processFunctionsByName)
.flatMap { (scope, symbols) ->
symbols.filter { it.doesOverrideBuiltinWithDifferentJvmName(scope, session) }
}
if (builtinSpecialFromSuperTypes.isEmpty()) return false
return builtinSpecialFromSuperTypes.any {
// Here `this` and `it` have different names but it's ok because override checker does not consider
// names of declarations at all
overrideChecker.isOverriddenFunction(this.fir, it.fir)
}
}
/**
* Checks if function is a valid override of JDK analogue of built-in method with erased value parameters (e.g. Map.containsKey(k: K))
*
* Examples:
* - boolean containsKey(Object key) -> true
* - boolean containsKey(K key) -> false // Wrong JDK method override, while it's a valid Kotlin built-in override
*
* There is a case when we shouldn't hide a function even if it overrides builtin member with value parameter erasure:
* if substituted kotlin overridden has the same parameters as current java override. Such situation may happen only in
* case when `Any`/`Object` is used as parameterization of supertype:
*
* // java
* class MySuperMap extends java.util.Map