FIR LC: create synthetic members of data class

This commit is contained in:
Jinseong Jeon
2021-09-24 00:41:15 -07:00
committed by Ilya Kirillov
parent c8047f8384
commit ac53166960
2 changed files with 74 additions and 1 deletions
@@ -10,12 +10,20 @@ import org.jetbrains.kotlin.analysis.api.isValid
import org.jetbrains.kotlin.analysis.api.symbols.*
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolKind
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithVisibility
import org.jetbrains.kotlin.asJava.builder.LightMemberOriginForDeclaration
import org.jetbrains.kotlin.asJava.classes.METHOD_INDEX_BASE
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.builtins.StandardNames.DATA_CLASS_COPY
import org.jetbrains.kotlin.builtins.StandardNames.HASHCODE_NAME
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.light.classes.symbol.classes.*
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKind
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(
@@ -96,6 +104,12 @@ internal class FirLightClassForSymbol(
filterNot {
it is KtKotlinPropertySymbol && it.isConst
}
}.applyIf(classOrObjectSymbol.isData) {
// Technically, synthetic members of `data` class, such as `componentN` or `copy`, are visible.
// They're just needed to be added later (to be in a backward-compatible order of members).
filterNot { function ->
function is KtFunctionSymbol && function.origin == KtSymbolOrigin.SOURCE_MEMBER_GENERATED
}
}
val suppressStatic = classOrObjectSymbol.classKind == KtClassKind.COMPANION_OBJECT
@@ -106,6 +120,8 @@ internal class FirLightClassForSymbol(
addMethodsFromCompanionIfNeeded(result)
addMethodsFromDataClass(result)
result
}
@@ -120,6 +136,62 @@ internal class FirLightClassForSymbol(
}
}
private fun addMethodsFromDataClass(result: MutableList<KtLightMethod>) {
if (!classOrObjectSymbol.isData) return
fun createMethodFromAny(ktFunctionSymbol: KtFunctionSymbol) {
// Similar to `copy`, synthetic members from `Any` should refer to `data` class as origin, not the function in `Any`.
val lightMemberOrigin = LightMemberOriginForDeclaration(this.kotlinOrigin!!, JvmDeclarationOriginKind.OTHER)
result.add(
FirLightSimpleMethodForSymbol(
functionSymbol = ktFunctionSymbol,
lightMemberOrigin = lightMemberOrigin,
containingClass = this,
isTopLevel = false,
methodIndex = METHOD_INDEX_BASE,
suppressStatic = false
)
)
}
analyzeWithSymbolAsContext(classOrObjectSymbol) {
val componentAndCopyFunctions = mutableListOf<KtFunctionSymbol>()
val functionsFromAny = mutableMapOf<Name, KtFunctionSymbol>()
// NB: componentN and copy are added during RAW FIR, but synthetic members from `Any` are not.
// Thus, using declared member scope is not sufficient to lookup "all" synthetic members.
classOrObjectSymbol.getMemberScope().getCallableSymbols().forEach { symbol ->
if (symbol is KtFunctionSymbol) {
val name = symbol.name
if (name.isCopy || name.isComponentN) {
componentAndCopyFunctions.add(symbol)
}
if (name.isFromAny) {
functionsFromAny[name] = symbol
}
}
}
createMethods(componentAndCopyFunctions.asSequence(), result)
// NB: functions from `Any` are not in an alphabetic order.
functionsFromAny[TO_STRING]?.let { createMethodFromAny(it) }
functionsFromAny[HASHCODE_NAME]?.let { createMethodFromAny(it) }
functionsFromAny[EQUALS]?.let { createMethodFromAny(it) }
}
}
private val Name.isCopy: Boolean
get() = this == DATA_CLASS_COPY
private val Name.isComponentN: Boolean
get() {
if (isSpecial) return false
if (!identifier.startsWith("component")) return false
val n = identifier.substring("component".length).toIntOrNull()
return n != null && n > 0
}
private val Name.isFromAny: Boolean
get() = this == EQUALS || this == HASHCODE_NAME || this == TO_STRING
private val _ownFields: List<KtLightField> by lazyPub {
val result = mutableListOf<KtLightField>()
@@ -54,7 +54,8 @@ internal abstract class FirLightMethodForSymbol(
override fun getParameterList(): PsiParameterList = _parametersList
override val kotlinOrigin: KtDeclaration? = functionSymbol.psi as? KtDeclaration
override val kotlinOrigin: KtDeclaration? =
lightMemberOrigin?.originalElement ?: functionSymbol.psi as? KtDeclaration
override fun isValid(): Boolean = super.isValid() && functionSymbol.isValid()
}