FIR Java: support Java setters more properly in use-site scope

This commit is contained in:
Mikhail Glukhikh
2020-09-24 16:55:48 +03:00
parent 873ea560a9
commit 368de43623
4 changed files with 56 additions and 39 deletions
@@ -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"
}
}
@@ -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
@@ -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 {