From cc0e39ebca98c38be4fab963f4ab3700f97c56e8 Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Wed, 5 Feb 2020 16:41:52 +0300 Subject: [PATCH] [FIR] Support synthetic property setters --- .../kotlin/fir/resolve/calls/Synthetics.kt | 53 ++++++++++++++----- .../problems/propertyFromJavaPlusAssign.kt | 2 +- .../problems/propertyFromJavaPlusAssign.txt | 2 +- .../synthetic/FirSyntheticProperty.kt | 14 ++--- .../javaProperties/AbbreviationName.fir.kt | 2 +- .../javaProperties/GenericClass.fir.kt | 2 +- .../javaProperties/KotlinOverridesJava.fir.kt | 2 +- 7 files changed, 53 insertions(+), 24 deletions(-) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Synthetics.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Synthetics.kt index 7fe8125811b..ad60c1f11c4 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Synthetics.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Synthetics.kt @@ -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, 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()?.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" diff --git a/compiler/fir/resolve/testData/resolve/problems/propertyFromJavaPlusAssign.kt b/compiler/fir/resolve/testData/resolve/problems/propertyFromJavaPlusAssign.kt index 251e656ef02..bd8a257c737 100644 --- a/compiler/fir/resolve/testData/resolve/problems/propertyFromJavaPlusAssign.kt +++ b/compiler/fir/resolve/testData/resolve/problems/propertyFromJavaPlusAssign.kt @@ -18,5 +18,5 @@ public class B { // FILE: main.kt fun test(b: B) { - b.text += "" + b.text += "" } \ No newline at end of file diff --git a/compiler/fir/resolve/testData/resolve/problems/propertyFromJavaPlusAssign.txt b/compiler/fir/resolve/testData/resolve/problems/propertyFromJavaPlusAssign.txt index 1767d0a4345..93cf5fc8967 100644 --- a/compiler/fir/resolve/testData/resolve/problems/propertyFromJavaPlusAssign.txt +++ b/compiler/fir/resolve/testData/resolve/problems/propertyFromJavaPlusAssign.txt @@ -1,4 +1,4 @@ FILE: main.kt public final fun test(b: R|B|): R|kotlin/Unit| { - # = R|/b|.R|/B.text|.R|kotlin/String.plus|(String()) + R|/B.text| = R|/b|.R|/B.text|.R|kotlin/String.plus|(String()) } diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/synthetic/FirSyntheticProperty.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/synthetic/FirSyntheticProperty.kt index 48f28e11aa6..cf74b7cb12b 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/synthetic/FirSyntheticProperty.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/synthetic/FirSyntheticProperty.kt @@ -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? diff --git a/compiler/testData/diagnostics/tests/syntheticExtensions/javaProperties/AbbreviationName.fir.kt b/compiler/testData/diagnostics/tests/syntheticExtensions/javaProperties/AbbreviationName.fir.kt index 112e586c4da..2c812f9d52b 100644 --- a/compiler/testData/diagnostics/tests/syntheticExtensions/javaProperties/AbbreviationName.fir.kt +++ b/compiler/testData/diagnostics/tests/syntheticExtensions/javaProperties/AbbreviationName.fir.kt @@ -1,7 +1,7 @@ // FILE: KotlinFile.kt fun foo(javaClass: JavaClass) { javaClass.url = javaClass.url + "/" - javaClass.htmlFile += "1" + javaClass.htmlFile += "1" javaClass.URL javaClass.uRL diff --git a/compiler/testData/diagnostics/tests/syntheticExtensions/javaProperties/GenericClass.fir.kt b/compiler/testData/diagnostics/tests/syntheticExtensions/javaProperties/GenericClass.fir.kt index 3d0b46e41d4..71a600c59a2 100644 --- a/compiler/testData/diagnostics/tests/syntheticExtensions/javaProperties/GenericClass.fir.kt +++ b/compiler/testData/diagnostics/tests/syntheticExtensions/javaProperties/GenericClass.fir.kt @@ -1,6 +1,6 @@ // FILE: KotlinFile.kt fun foo(javaClass: JavaClass) { - javaClass.something += "x" + javaClass.something += "x" } // FILE: JavaClass.java diff --git a/compiler/testData/diagnostics/tests/syntheticExtensions/javaProperties/KotlinOverridesJava.fir.kt b/compiler/testData/diagnostics/tests/syntheticExtensions/javaProperties/KotlinOverridesJava.fir.kt index 87f6b599442..99d47ef1928 100644 --- a/compiler/testData/diagnostics/tests/syntheticExtensions/javaProperties/KotlinOverridesJava.fir.kt +++ b/compiler/testData/diagnostics/tests/syntheticExtensions/javaProperties/KotlinOverridesJava.fir.kt @@ -22,7 +22,7 @@ fun foo(k: KotlinClass) { useString(k.something3) k.setSomething4("") - k.something4 += "" + k.something4 += "" k.setSomething4(null) k.something4 = null