FIR Java: support Java setters more properly in use-site scope
This commit is contained in:
+29
-27
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.fir.scopes.getContainingClassifierNamesIfPresent
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.AbstractFirUseSiteMemberScope
|
||||
import org.jetbrains.kotlin.fir.symbols.CallableId
|
||||
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.name.Name
|
||||
|
||||
@@ -58,33 +59,19 @@ class JavaClassUseSiteMemberScope(
|
||||
}
|
||||
|
||||
private fun generateAccessorSymbol(
|
||||
functionSymbol: FirFunctionSymbol<*>,
|
||||
getterSymbol: FirNamedFunctionSymbol,
|
||||
setterSymbol: FirNamedFunctionSymbol?,
|
||||
syntheticPropertyName: Name,
|
||||
isGetter: Boolean
|
||||
): FirAccessorSymbol? {
|
||||
if (functionSymbol !is FirNamedFunctionSymbol) {
|
||||
return null
|
||||
}
|
||||
val fir = functionSymbol.fir
|
||||
if (fir.isStatic) {
|
||||
return null
|
||||
}
|
||||
when (isGetter) {
|
||||
true -> if (fir.valueParameters.isNotEmpty()) {
|
||||
return null
|
||||
}
|
||||
false -> if (fir.valueParameters.size != 1) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
return buildSyntheticProperty {
|
||||
session = this@JavaClassUseSiteMemberScope.session
|
||||
name = syntheticPropertyName
|
||||
symbol = FirAccessorSymbol(
|
||||
accessorId = functionSymbol.callableId,
|
||||
callableId = CallableId(functionSymbol.callableId.packageName, functionSymbol.callableId.className, syntheticPropertyName)
|
||||
accessorId = getterSymbol.callableId,
|
||||
callableId = CallableId(getterSymbol.callableId.packageName, getterSymbol.callableId.className, syntheticPropertyName)
|
||||
)
|
||||
delegateGetter = fir
|
||||
delegateGetter = getterSymbol.fir
|
||||
delegateSetter = setterSymbol?.fir
|
||||
}.symbol
|
||||
}
|
||||
|
||||
@@ -103,9 +90,28 @@ class JavaClassUseSiteMemberScope(
|
||||
|
||||
if (klass is FirJavaClass) {
|
||||
for (getterName in getterNames) {
|
||||
var getterSymbol: FirNamedFunctionSymbol? = null
|
||||
var setterSymbol: FirNamedFunctionSymbol? = null
|
||||
declaredMemberScope.processFunctionsByName(getterName) { functionSymbol ->
|
||||
if (getterSymbol == null && functionSymbol is FirNamedFunctionSymbol) {
|
||||
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 && functionSymbol is FirNamedFunctionSymbol) {
|
||||
val function = functionSymbol.fir
|
||||
if (!function.isStatic && function.returnTypeRef.isUnit && function.valueParameters.size == 1) {
|
||||
setterSymbol = functionSymbol
|
||||
}
|
||||
}
|
||||
}
|
||||
val accessorSymbol = generateAccessorSymbol(
|
||||
functionSymbol, propertyName, isGetter = true
|
||||
getterSymbol!!, setterSymbol, propertyName
|
||||
)
|
||||
if (accessorSymbol != null) {
|
||||
// NB: accessor should not be processed directly unless we find matching property symbol in supertype
|
||||
@@ -158,7 +164,6 @@ class JavaClassUseSiteMemberScope(
|
||||
return processAccessorFunctionsAndPropertiesByName(name, emptyList(), processor)
|
||||
}
|
||||
val getterNames = FirJavaSyntheticNamesProvider.possibleGetterNamesByPropertyName(name)
|
||||
val setterName = Name.identifier(SETTER_PREFIX + name.identifier.capitalize())
|
||||
return processAccessorFunctionsAndPropertiesByName(name, getterNames, processor)
|
||||
}
|
||||
|
||||
@@ -169,7 +174,8 @@ class JavaClassUseSiteMemberScope(
|
||||
val potentialPropertyName = session.syntheticNamesProvider.propertyNameByAccessorName(name)
|
||||
?: return super.processFunctionsByName(name, processor)
|
||||
val accessors = mutableListOf<FirAccessorSymbol>()
|
||||
processAccessorFunctionsAndPropertiesByName(potentialPropertyName, listOf(name)) {
|
||||
val getterName = session.syntheticNamesProvider.getterNameBySetterName(name) ?: name
|
||||
processAccessorFunctionsAndPropertiesByName(potentialPropertyName, listOf(getterName)) {
|
||||
if (it is FirAccessorSymbol) {
|
||||
accessors += it
|
||||
}
|
||||
@@ -188,8 +194,4 @@ class JavaClassUseSiteMemberScope(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val SETTER_PREFIX = "set"
|
||||
}
|
||||
}
|
||||
|
||||
+11
-2
@@ -32,16 +32,25 @@ object FirJavaSyntheticNamesProvider : FirSyntheticNamesProvider() {
|
||||
}
|
||||
}
|
||||
|
||||
override fun setterNameByGetterName(name: Name): Name {
|
||||
override fun setterNameByGetterName(name: Name): Name? {
|
||||
val identifier = name.identifier
|
||||
val prefix = when {
|
||||
identifier.startsWith(GETTER_PREFIX) -> GETTER_PREFIX
|
||||
identifier.startsWith(IS_PREFIX) -> IS_PREFIX
|
||||
else -> throw IllegalArgumentException()
|
||||
else -> return null
|
||||
}
|
||||
return Name.identifier(SETTER_PREFIX + identifier.removePrefix(prefix))
|
||||
}
|
||||
|
||||
override fun getterNameBySetterName(name: Name): Name? {
|
||||
val identifier = name.identifier
|
||||
val prefix = when {
|
||||
identifier.startsWith(SETTER_PREFIX) -> SETTER_PREFIX
|
||||
else -> return null
|
||||
}
|
||||
return Name.identifier(GETTER_PREFIX + identifier.removePrefix(prefix))
|
||||
}
|
||||
|
||||
override fun propertyNameByAccessorName(name: Name): Name? {
|
||||
if (name.isSpecial) return null
|
||||
val identifier = name.identifier
|
||||
|
||||
+2
-1
@@ -11,7 +11,8 @@ import org.jetbrains.kotlin.name.Name
|
||||
|
||||
abstract class FirSyntheticNamesProvider : FirSessionComponent {
|
||||
abstract fun possibleGetterNamesByPropertyName(name: Name): List<Name>
|
||||
abstract fun setterNameByGetterName(name: Name): Name
|
||||
abstract fun setterNameByGetterName(name: Name): Name?
|
||||
abstract fun getterNameBySetterName(name: Name): Name?
|
||||
abstract fun propertyNameByAccessorName(name: Name): Name?
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ import org.jetbrains.kotlin.fir.symbols.StandardClassIds
|
||||
import org.jetbrains.kotlin.fir.symbols.SyntheticSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.types.ConeNullability.NOT_NULL
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
class SyntheticPropertySymbol(
|
||||
@@ -64,15 +65,19 @@ class FirSyntheticPropertiesScope(
|
||||
var matchingSetter: FirSimpleFunction? = null
|
||||
if (getterReturnType != null) {
|
||||
val setterName = syntheticNamesProvider.setterNameByGetterName(getterName)
|
||||
baseScope.processFunctionsByName(setterName, fun(setterSymbol: FirFunctionSymbol<*>) {
|
||||
if (matchingSetter != null) return
|
||||
val setter = setterSymbol.fir as? FirSimpleFunction ?: return
|
||||
val parameter = setter.valueParameters.singleOrNull() ?: return
|
||||
if (setter.typeParameters.isNotEmpty() || setter.isStatic) return
|
||||
val parameterType = (parameter.returnTypeRef as? FirResolvedTypeRef)?.type ?: return
|
||||
if (getterReturnType.withNullability(ConeNullability.NOT_NULL) != parameterType.withNullability(ConeNullability.NOT_NULL)) return
|
||||
matchingSetter = setter
|
||||
})
|
||||
if (setterName != null) {
|
||||
baseScope.processFunctionsByName(setterName, fun(setterSymbol: FirFunctionSymbol<*>) {
|
||||
if (matchingSetter != null) return
|
||||
val setter = setterSymbol.fir as? FirSimpleFunction ?: return
|
||||
val parameter = setter.valueParameters.singleOrNull() ?: return
|
||||
if (setter.typeParameters.isNotEmpty() || setter.isStatic) return
|
||||
val parameterType = (parameter.returnTypeRef as? FirResolvedTypeRef)?.type ?: return
|
||||
if (getterReturnType.withNullability(NOT_NULL) != parameterType.withNullability(NOT_NULL)) {
|
||||
return
|
||||
}
|
||||
matchingSetter = setter
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
val property = buildSyntheticProperty {
|
||||
|
||||
Reference in New Issue
Block a user