[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.impl.*
|
||||
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.name.Name
|
||||
import org.jetbrains.kotlin.util.capitalizeDecapitalize.capitalizeAsciiOnly
|
||||
@@ -38,24 +38,41 @@ class FirSyntheticPropertiesScope(
|
||||
val synthetic: MutableMap<FirCallableSymbol<*>, FirVariableSymbol<*>> = mutableMapOf()
|
||||
|
||||
private fun checkGetAndCreateSynthetic(
|
||||
name: Name,
|
||||
symbol: FirFunctionSymbol<*>,
|
||||
propertyName: Name,
|
||||
getterName: Name,
|
||||
getterSymbol: FirFunctionSymbol<*>,
|
||||
processor: (FirVariableSymbol<*>) -> Unit
|
||||
) {
|
||||
val fir = symbol.fir as? FirSimpleFunction ?: return
|
||||
val getter = getterSymbol.fir as? FirSimpleFunction ?: return
|
||||
|
||||
if (fir.typeParameters.isNotEmpty()) return
|
||||
if (fir.valueParameters.isNotEmpty()) return
|
||||
if (fir.isStatic) return
|
||||
if (fir.returnTypeRef.coneTypeSafe<ConeClassLikeType>()?.lookupTag?.classId == StandardClassIds.Unit) return
|
||||
if (getter.typeParameters.isNotEmpty()) return
|
||||
if (getter.valueParameters.isNotEmpty()) return
|
||||
if (getter.isStatic) 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(
|
||||
session, name,
|
||||
session, propertyName,
|
||||
symbol = SyntheticPropertySymbol(
|
||||
accessorId = symbol.callableId,
|
||||
callableId = CallableId(symbol.callableId.packageName, symbol.callableId.className, name)
|
||||
accessorId = getterSymbol.callableId,
|
||||
callableId = CallableId(getterSymbol.callableId.packageName, getterSymbol.callableId.className, propertyName)
|
||||
),
|
||||
delegateGetter = fir
|
||||
delegateGetter = getter,
|
||||
delegateSetter = matchingSetter
|
||||
)
|
||||
processor(property.symbol)
|
||||
}
|
||||
@@ -64,7 +81,7 @@ class FirSyntheticPropertiesScope(
|
||||
val getterNames = possibleGetterNamesByPropertyName(name)
|
||||
for (getterName in getterNames) {
|
||||
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 IS_PREFIX = "is"
|
||||
|
||||
+1
-1
@@ -18,5 +18,5 @@ public class B {
|
||||
// FILE: main.kt
|
||||
|
||||
fun test(b: B) {
|
||||
b.<!VARIABLE_EXPECTED!>text<!> += ""
|
||||
b.text += ""
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
FILE: main.kt
|
||||
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.serialization.deserialization.descriptors.DeserializedContainerSource
|
||||
|
||||
class FirSyntheticProperty(
|
||||
class FirSyntheticProperty private constructor(
|
||||
override val session: FirSession,
|
||||
override val returnTypeRef: FirTypeRef,
|
||||
override val name: Name,
|
||||
@@ -41,12 +41,14 @@ class FirSyntheticProperty(
|
||||
session: FirSession,
|
||||
name: Name,
|
||||
symbol: FirAccessorSymbol,
|
||||
delegateGetter: FirSimpleFunction
|
||||
delegateGetter: FirSimpleFunction,
|
||||
delegateSetter: FirSimpleFunction? = null
|
||||
) : this(
|
||||
session, delegateGetter.returnTypeRef, name, false, symbol,
|
||||
FirDeclarationStatusImpl(delegateGetter.visibility, delegateGetter.modality),
|
||||
delegateGetter.resolvePhase,
|
||||
FirSyntheticPropertyAccessor(delegateGetter, isGetter = true)
|
||||
session, delegateGetter.returnTypeRef, name, isVar = delegateSetter != null, symbol = symbol,
|
||||
status = FirDeclarationStatusImpl(delegateGetter.visibility, delegateGetter.modality),
|
||||
resolvePhase = delegateGetter.resolvePhase,
|
||||
getter = FirSyntheticPropertyAccessor(delegateGetter, isGetter = true),
|
||||
setter = delegateSetter?.let { FirSyntheticPropertyAccessor(it, isGetter = false) }
|
||||
)
|
||||
|
||||
override val source: FirSourceElement?
|
||||
|
||||
Vendored
+1
-1
@@ -1,7 +1,7 @@
|
||||
// FILE: KotlinFile.kt
|
||||
fun foo(javaClass: JavaClass) {
|
||||
javaClass.url = javaClass.url + "/"
|
||||
javaClass.<!VARIABLE_EXPECTED!>htmlFile<!> += "1"
|
||||
javaClass.htmlFile += "1"
|
||||
|
||||
javaClass.<!UNRESOLVED_REFERENCE!>URL<!>
|
||||
javaClass.<!UNRESOLVED_REFERENCE!>uRL<!>
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
// FILE: KotlinFile.kt
|
||||
fun foo(javaClass: JavaClass<String>) {
|
||||
javaClass.<!VARIABLE_EXPECTED!>something<!> += "x"
|
||||
javaClass.something += "x"
|
||||
}
|
||||
|
||||
// FILE: JavaClass.java
|
||||
|
||||
Vendored
+1
-1
@@ -22,7 +22,7 @@ fun foo(k: KotlinClass) {
|
||||
useString(k.something3)
|
||||
|
||||
k.setSomething4("")
|
||||
k.<!VARIABLE_EXPECTED!>something4<!> += ""
|
||||
k.something4 += ""
|
||||
k.<!INAPPLICABLE_CANDIDATE!>setSomething4<!>(null)
|
||||
k.something4 = null
|
||||
|
||||
|
||||
Reference in New Issue
Block a user