From 5880d80d266c1cc792e93b5e2862795543da6a17 Mon Sep 17 00:00:00 2001 From: Jinseong Jeon Date: Wed, 27 Oct 2021 18:13:15 -0700 Subject: [PATCH] FIR LC: add support for inline class --- .../symbol/classes/FirLightClassForSymbol.kt | 2 +- .../symbol/classes/FirLightInlineClass.kt | 67 +++++++++++++++++++ .../symbol/classes/firLightClassUtils.kt | 9 ++- .../asJava/classes/KtUltraInlineLightClass.kt | 3 + .../asJava/ultraLightClasses/inlineClasses.kt | 4 +- 5 files changed, 81 insertions(+), 4 deletions(-) create mode 100644 analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/classes/FirLightInlineClass.kt diff --git a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/classes/FirLightClassForSymbol.kt b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/classes/FirLightClassForSymbol.kt index 5a3b21980f6..8a17ef7d3f7 100644 --- a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/classes/FirLightClassForSymbol.kt +++ b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/classes/FirLightClassForSymbol.kt @@ -28,7 +28,7 @@ import org.jetbrains.kotlin.util.OperatorNameConventions.EQUALS import org.jetbrains.kotlin.util.OperatorNameConventions.TO_STRING import org.jetbrains.kotlin.utils.addToStdlib.applyIf -internal class FirLightClassForSymbol( +internal open class FirLightClassForSymbol( private val classOrObjectSymbol: KtNamedClassOrObjectSymbol, manager: PsiManager ) : FirLightClassForClassOrObjectSymbol(classOrObjectSymbol, manager) { diff --git a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/classes/FirLightInlineClass.kt b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/classes/FirLightInlineClass.kt new file mode 100644 index 00000000000..cf738618455 --- /dev/null +++ b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/classes/FirLightInlineClass.kt @@ -0,0 +1,67 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.light.classes.symbol + +import com.intellij.psi.PsiManager +import com.intellij.psi.PsiMethod +import org.jetbrains.kotlin.analysis.api.symbols.KtFunctionSymbol +import org.jetbrains.kotlin.analysis.api.symbols.KtNamedClassOrObjectSymbol +import org.jetbrains.kotlin.analysis.api.symbols.KtPropertySymbol +import org.jetbrains.kotlin.asJava.classes.lazyPub +import org.jetbrains.kotlin.asJava.elements.KtLightField +import org.jetbrains.kotlin.asJava.elements.KtLightMethod +import org.jetbrains.kotlin.light.classes.symbol.classes.createMethods +import org.jetbrains.kotlin.light.classes.symbol.classes.createPropertyAccessors +import org.jetbrains.kotlin.resolve.deprecation.DeprecationLevelValue + +internal class FirLightInlineClass( + private val classOrObjectSymbol: KtNamedClassOrObjectSymbol, + manager: PsiManager +) : FirLightClassForSymbol(classOrObjectSymbol, manager) { + + init { + require(classOrObjectSymbol.isInline) + } + + private val _ownMethods: List by lazyPub { + val result = mutableListOf() + + analyzeWithSymbolAsContext(classOrObjectSymbol) { + val declaredMemberScope = classOrObjectSymbol.getDeclaredMemberScope() + val applicableDeclarations = declaredMemberScope.getCallableSymbols() + .filter { + (it as? KtPropertySymbol)?.isOverride == true || (it as? KtFunctionSymbol)?.isOverride == true + } + .filterNot { + it.deprecationStatus?.deprecationLevel == DeprecationLevelValue.HIDDEN + } + + createMethods(applicableDeclarations, result, suppressStaticForMethods = false) + + val inlineClassParameterSymbol = + declaredMemberScope.getConstructors().singleOrNull { it.isPrimary }?.valueParameters?.singleOrNull() + if (inlineClassParameterSymbol != null) { + val propertySymbol = declaredMemberScope.getCallableSymbols { it == inlineClassParameterSymbol.name } + .singleOrNull { it is KtPropertySymbol && it.isFromPrimaryConstructor } as? KtPropertySymbol + if (propertySymbol != null) { + // (inline or) value class primary constructor must have only final read-only (val) property parameter + // Even though the property parameter is mutable (for some reasons, e.g., testing or not checked yet), + // we can enforce immutability here. + createPropertyAccessors(result, propertySymbol, isTopLevel = false, isMutable = false) + } + } + } + + result + } + + override fun getOwnMethods(): List = _ownMethods + + override fun getOwnFields(): List = emptyList() + + override fun copy(): FirLightInlineClass = + FirLightInlineClass(classOrObjectSymbol, manager) +} diff --git a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/classes/firLightClassUtils.kt b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/classes/firLightClassUtils.kt index 961a7b5b239..161ffa49acf 100644 --- a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/classes/firLightClassUtils.kt +++ b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/classes/firLightClassUtils.kt @@ -70,7 +70,11 @@ fun createFirLightClassNoCache(classOrObject: KtClassOrObject): KtLightClass? = return when { classOrObject is KtEnumEntry -> lightClassForEnumEntry(classOrObject) - classOrObject.hasModifier(KtTokens.INLINE_KEYWORD) -> return null //TODO + classOrObject.hasModifier(KtTokens.INLINE_KEYWORD) -> { + analyseForLightClasses(classOrObject) { + classOrObject.getNamedClassOrObjectSymbol()?.let { FirLightInlineClass(it, classOrObject.manager) } + } + } else -> { analyseForLightClasses(classOrObject) { classOrObject.getClassOrObjectSymbol().createLightClassNoCache(classOrObject.manager) @@ -210,6 +214,7 @@ internal fun FirLightClassBase.createPropertyAccessors( result: MutableList, declaration: KtPropertySymbol, isTopLevel: Boolean, + isMutable: Boolean = !declaration.isVal, ) { if (declaration is KtKotlinPropertySymbol && declaration.isConst) return @@ -258,7 +263,7 @@ internal fun FirLightClassBase.createPropertyAccessors( !isAnnotationType && it.needToCreateAccessor(AnnotationUseSiteTarget.PROPERTY_SETTER) } - if (setter != null) { + if (isMutable && setter != null) { val lightMemberOrigin = originalElement?.let { LightMemberOriginForDeclaration( originalElement = it, diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtUltraInlineLightClass.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtUltraInlineLightClass.kt index 4358b276a90..95112c2523f 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtUltraInlineLightClass.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtUltraInlineLightClass.kt @@ -57,6 +57,9 @@ class KtUltraLightInlineClass( if (inlineClassParameter != null) { membersBuilder.propertyAccessors( inlineClassParameter, + // (inline or) value class primary constructor must have only final read-only (val) property parameter + // Even though the property parameter is mutable (for some reasons, e.g., testing or not checked yet), + // we can enforce immutability here. mutable = false, forceStatic = false, onlyJvmStatic = false diff --git a/compiler/testData/asJava/ultraLightClasses/inlineClasses.kt b/compiler/testData/asJava/ultraLightClasses/inlineClasses.kt index ab77e06dd28..515a0380539 100644 --- a/compiler/testData/asJava/ultraLightClasses/inlineClasses.kt +++ b/compiler/testData/asJava/ultraLightClasses/inlineClasses.kt @@ -26,4 +26,6 @@ inline class InlineInheritance(val v: Int) : I { override val x get() = 5 fun z() = 7 -} \ No newline at end of file +} + +// FIR_COMPARISON