[FIR] Support synthetic property setters
This commit is contained in:
@@ -15,7 +15,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.ConeClassLikeType
|
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
||||||
import org.jetbrains.kotlin.fir.types.coneTypeSafe
|
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
|
||||||
import org.jetbrains.kotlin.load.java.propertyNameByGetMethodName
|
import org.jetbrains.kotlin.load.java.propertyNameByGetMethodName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.util.capitalizeDecapitalize.capitalizeAsciiOnly
|
import org.jetbrains.kotlin.util.capitalizeDecapitalize.capitalizeAsciiOnly
|
||||||
@@ -38,24 +38,41 @@ class FirSyntheticPropertiesScope(
|
|||||||
val synthetic: MutableMap<FirCallableSymbol<*>, FirVariableSymbol<*>> = mutableMapOf()
|
val synthetic: MutableMap<FirCallableSymbol<*>, FirVariableSymbol<*>> = mutableMapOf()
|
||||||
|
|
||||||
private fun checkGetAndCreateSynthetic(
|
private fun checkGetAndCreateSynthetic(
|
||||||
name: Name,
|
propertyName: Name,
|
||||||
symbol: FirFunctionSymbol<*>,
|
getterName: Name,
|
||||||
|
getterSymbol: FirFunctionSymbol<*>,
|
||||||
processor: (FirVariableSymbol<*>) -> Unit
|
processor: (FirVariableSymbol<*>) -> Unit
|
||||||
) {
|
) {
|
||||||
val fir = symbol.fir as? FirSimpleFunction ?: return
|
val getter = getterSymbol.fir as? FirSimpleFunction ?: return
|
||||||
|
|
||||||
if (fir.typeParameters.isNotEmpty()) return
|
if (getter.typeParameters.isNotEmpty()) return
|
||||||
if (fir.valueParameters.isNotEmpty()) return
|
if (getter.valueParameters.isNotEmpty()) return
|
||||||
if (fir.isStatic) return
|
if (getter.isStatic) return
|
||||||
if (fir.returnTypeRef.coneTypeSafe<ConeClassLikeType>()?.lookupTag?.classId == StandardClassIds.Unit) return
|
val getterReturnType = (getter.returnTypeRef as? FirResolvedTypeRef)?.type
|
||||||
|
if ((getterReturnType as? ConeClassLikeType)?.lookupTag?.classId == StandardClassIds.Unit) return
|
||||||
|
|
||||||
|
var matchingSetter: FirSimpleFunction? = null
|
||||||
|
if (getterReturnType != null) {
|
||||||
|
val setterName = 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 (parameterType != getterReturnType) return
|
||||||
|
matchingSetter = setter
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
val property = FirSyntheticProperty(
|
val property = FirSyntheticProperty(
|
||||||
session, name,
|
session, propertyName,
|
||||||
symbol = SyntheticPropertySymbol(
|
symbol = SyntheticPropertySymbol(
|
||||||
accessorId = symbol.callableId,
|
accessorId = getterSymbol.callableId,
|
||||||
callableId = CallableId(symbol.callableId.packageName, symbol.callableId.className, name)
|
callableId = CallableId(getterSymbol.callableId.packageName, getterSymbol.callableId.className, propertyName)
|
||||||
),
|
),
|
||||||
delegateGetter = fir
|
delegateGetter = getter,
|
||||||
|
delegateSetter = matchingSetter
|
||||||
)
|
)
|
||||||
processor(property.symbol)
|
processor(property.symbol)
|
||||||
}
|
}
|
||||||
@@ -64,7 +81,7 @@ class FirSyntheticPropertiesScope(
|
|||||||
val getterNames = possibleGetterNamesByPropertyName(name)
|
val getterNames = possibleGetterNamesByPropertyName(name)
|
||||||
for (getterName in getterNames) {
|
for (getterName in getterNames) {
|
||||||
baseScope.processFunctionsByName(getterName) {
|
baseScope.processFunctionsByName(getterName) {
|
||||||
checkGetAndCreateSynthetic(name, it, processor)
|
checkGetAndCreateSynthetic(name, getterName, it, processor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -84,6 +101,16 @@ class FirSyntheticPropertiesScope(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun setterNameByGetterName(name: Name): Name {
|
||||||
|
val identifier = name.identifier
|
||||||
|
val prefix = when {
|
||||||
|
identifier.startsWith("get") -> "get"
|
||||||
|
identifier.startsWith("is") -> "is"
|
||||||
|
else -> throw IllegalArgumentException()
|
||||||
|
}
|
||||||
|
return Name.identifier("set" + identifier.removePrefix(prefix))
|
||||||
|
}
|
||||||
|
|
||||||
private const val GETTER_PREFIX = "get"
|
private const val GETTER_PREFIX = "get"
|
||||||
|
|
||||||
private const val IS_PREFIX = "is"
|
private const val IS_PREFIX = "is"
|
||||||
|
|||||||
+1
-1
@@ -18,5 +18,5 @@ public class B {
|
|||||||
// FILE: main.kt
|
// FILE: main.kt
|
||||||
|
|
||||||
fun test(b: B) {
|
fun test(b: B) {
|
||||||
b.<!VARIABLE_EXPECTED!>text<!> += ""
|
b.text += ""
|
||||||
}
|
}
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
FILE: main.kt
|
FILE: main.kt
|
||||||
public final fun test(b: R|B|): R|kotlin/Unit| {
|
public final fun test(b: R|B|): R|kotlin/Unit| {
|
||||||
<Variable expected># = R|<local>/b|.R|/B.text|.R|kotlin/String.plus|(String())
|
R|/B.text| = R|<local>/b|.R|/B.text|.R|kotlin/String.plus|(String())
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-6
@@ -22,7 +22,7 @@ import org.jetbrains.kotlin.fir.visitors.FirVisitor
|
|||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource
|
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource
|
||||||
|
|
||||||
class FirSyntheticProperty(
|
class FirSyntheticProperty private constructor(
|
||||||
override val session: FirSession,
|
override val session: FirSession,
|
||||||
override val returnTypeRef: FirTypeRef,
|
override val returnTypeRef: FirTypeRef,
|
||||||
override val name: Name,
|
override val name: Name,
|
||||||
@@ -41,12 +41,14 @@ class FirSyntheticProperty(
|
|||||||
session: FirSession,
|
session: FirSession,
|
||||||
name: Name,
|
name: Name,
|
||||||
symbol: FirAccessorSymbol,
|
symbol: FirAccessorSymbol,
|
||||||
delegateGetter: FirSimpleFunction
|
delegateGetter: FirSimpleFunction,
|
||||||
|
delegateSetter: FirSimpleFunction? = null
|
||||||
) : this(
|
) : this(
|
||||||
session, delegateGetter.returnTypeRef, name, false, symbol,
|
session, delegateGetter.returnTypeRef, name, isVar = delegateSetter != null, symbol = symbol,
|
||||||
FirDeclarationStatusImpl(delegateGetter.visibility, delegateGetter.modality),
|
status = FirDeclarationStatusImpl(delegateGetter.visibility, delegateGetter.modality),
|
||||||
delegateGetter.resolvePhase,
|
resolvePhase = delegateGetter.resolvePhase,
|
||||||
FirSyntheticPropertyAccessor(delegateGetter, isGetter = true)
|
getter = FirSyntheticPropertyAccessor(delegateGetter, isGetter = true),
|
||||||
|
setter = delegateSetter?.let { FirSyntheticPropertyAccessor(it, isGetter = false) }
|
||||||
)
|
)
|
||||||
|
|
||||||
override val source: FirSourceElement?
|
override val source: FirSourceElement?
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
// FILE: KotlinFile.kt
|
// FILE: KotlinFile.kt
|
||||||
fun foo(javaClass: JavaClass) {
|
fun foo(javaClass: JavaClass) {
|
||||||
javaClass.url = javaClass.url + "/"
|
javaClass.url = javaClass.url + "/"
|
||||||
javaClass.<!VARIABLE_EXPECTED!>htmlFile<!> += "1"
|
javaClass.htmlFile += "1"
|
||||||
|
|
||||||
javaClass.<!UNRESOLVED_REFERENCE!>URL<!>
|
javaClass.<!UNRESOLVED_REFERENCE!>URL<!>
|
||||||
javaClass.<!UNRESOLVED_REFERENCE!>uRL<!>
|
javaClass.<!UNRESOLVED_REFERENCE!>uRL<!>
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
// FILE: KotlinFile.kt
|
// FILE: KotlinFile.kt
|
||||||
fun foo(javaClass: JavaClass<String>) {
|
fun foo(javaClass: JavaClass<String>) {
|
||||||
javaClass.<!VARIABLE_EXPECTED!>something<!> += "x"
|
javaClass.something += "x"
|
||||||
}
|
}
|
||||||
|
|
||||||
// FILE: JavaClass.java
|
// FILE: JavaClass.java
|
||||||
|
|||||||
Vendored
+1
-1
@@ -22,7 +22,7 @@ fun foo(k: KotlinClass) {
|
|||||||
useString(k.something3)
|
useString(k.something3)
|
||||||
|
|
||||||
k.setSomething4("")
|
k.setSomething4("")
|
||||||
k.<!VARIABLE_EXPECTED!>something4<!> += ""
|
k.something4 += ""
|
||||||
k.<!INAPPLICABLE_CANDIDATE!>setSomething4<!>(null)
|
k.<!INAPPLICABLE_CANDIDATE!>setSomething4<!>(null)
|
||||||
k.something4 = null
|
k.something4 = null
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user