FIR LC: create synthetic members of data class
This commit is contained in:
committed by
Ilya Kirillov
parent
c8047f8384
commit
ac53166960
+72
@@ -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>()
|
||||
|
||||
+2
-1
@@ -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()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user