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