[FIR] Support synthetic property setters

This commit is contained in:
Mikhail Glukhikh
2020-02-05 16:41:52 +03:00
parent a9ba94cf0e
commit cc0e39ebca
7 changed files with 53 additions and 24 deletions
@@ -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"
@@ -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,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())
} }
@@ -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?
@@ -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,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
@@ -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