Fix missing declarations in declaration stack

This commit is contained in:
Tamas Vajk
2022-01-19 11:47:34 +01:00
committed by Ian Lynagh
parent 482a37cfe3
commit 52597e5d63

View File

@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlin.types.Variance
import java.io.Closeable
import java.util.*
open class KotlinFileExtractor(
@@ -271,56 +272,59 @@ open class KotlinFileExtractor(
}
fun extractClassSource(c: IrClass): Label<out DbClassorinterface> {
val id = if (c.isAnonymousObject) {
@Suppress("UNCHECKED_CAST")
useAnonymousClass(c).javaResult.id as Label<out DbClass>
} else {
useClassSource(c)
}
val pkg = c.packageFqName?.asString() ?: ""
val cls = if (c.isAnonymousObject) "" else c.name.asString()
val pkgId = extractPackage(pkg)
if(c.kind == ClassKind.INTERFACE) {
@Suppress("UNCHECKED_CAST")
val interfaceId = id as Label<out DbInterface>
tw.writeInterfaces(interfaceId, cls, pkgId, interfaceId)
} else {
@Suppress("UNCHECKED_CAST")
val classId = id as Label<out DbClass>
tw.writeClasses(classId, cls, pkgId, classId)
DeclarationStackAdjuster(c).use {
if (c.kind == ClassKind.ENUM_CLASS) {
tw.writeIsEnumType(classId)
val id = if (c.isAnonymousObject) {
@Suppress("UNCHECKED_CAST")
useAnonymousClass(c).javaResult.id as Label<out DbClass>
} else {
useClassSource(c)
}
val pkg = c.packageFqName?.asString() ?: ""
val cls = if (c.isAnonymousObject) "" else c.name.asString()
val pkgId = extractPackage(pkg)
if (c.kind == ClassKind.INTERFACE) {
@Suppress("UNCHECKED_CAST")
val interfaceId = id as Label<out DbInterface>
tw.writeInterfaces(interfaceId, cls, pkgId, interfaceId)
} else {
@Suppress("UNCHECKED_CAST")
val classId = id as Label<out DbClass>
tw.writeClasses(classId, cls, pkgId, classId)
if (c.kind == ClassKind.ENUM_CLASS) {
tw.writeIsEnumType(classId)
}
}
val locId = tw.getLocation(c)
tw.writeHasLocation(id, locId)
extractEnclosingClass(c, id, locId, listOf())
c.typeParameters.mapIndexed { idx, it -> extractTypeParameter(it, idx) }
c.declarations.map { extractDeclaration(it) }
extractObjectInitializerFunction(c, id)
if (c.isNonCompanionObject) {
// For `object MyObject { ... }`, the .class has an
// automatically-generated `public static final MyObject INSTANCE`
// field that may be referenced from Java code, and is used in our
// IrGetObjectValue support. We therefore need to fabricate it
// here.
val instance = useObjectClassInstance(c)
val type = useSimpleTypeClass(c, emptyList(), false)
tw.writeFields(instance.id, instance.name, type.javaResult.id, type.kotlinResult.id, id, instance.id)
tw.writeHasLocation(instance.id, locId)
addModifiers(instance.id, "public", "static", "final")
@Suppress("UNCHECKED_CAST")
tw.writeClass_object(id as Label<DbClass>, instance.id)
}
extractClassModifiers(c, id)
extractClassSupertypes(c, id)
return id
}
val locId = tw.getLocation(c)
tw.writeHasLocation(id, locId)
extractEnclosingClass(c, id, locId, listOf())
c.typeParameters.mapIndexed { idx, it -> extractTypeParameter(it, idx) }
c.declarations.map { extractDeclaration(it) }
extractObjectInitializerFunction(c, id)
if(c.isNonCompanionObject) {
// For `object MyObject { ... }`, the .class has an
// automatically-generated `public static final MyObject INSTANCE`
// field that may be referenced from Java code, and is used in our
// IrGetObjectValue support. We therefore need to fabricate it
// here.
val instance = useObjectClassInstance(c)
val type = useSimpleTypeClass(c, emptyList(), false)
tw.writeFields(instance.id, instance.name, type.javaResult.id, type.kotlinResult.id, id, instance.id)
tw.writeHasLocation(instance.id, locId)
addModifiers(instance.id, "public", "static", "final")
@Suppress("UNCHECKED_CAST")
tw.writeClass_object(id as Label<DbClass>, instance.id)
}
extractClassModifiers(c, id)
extractClassSupertypes(c, id)
return id
}
fun extractEnclosingClass(innerClass: IrClass, innerId: Label<out DbClassorinterface>, innerLocId: Label<DbLocation>, parentClassTypeArguments: List<IrTypeArgument>) {
@@ -482,81 +486,85 @@ open class KotlinFileExtractor(
}
fun extractFunction(f: IrFunction, parentId: Label<out DbReftype>, extractBody: Boolean, typeSubstitution: TypeSubstitution?, classTypeArgsIncludingOuterClasses: List<IrTypeArgument>?): Label<out DbCallable> {
declarationStack.push(f)
DeclarationStackAdjuster(f).use {
getFunctionTypeParameters(f).mapIndexed { idx, it -> extractTypeParameter(it, idx) }
getFunctionTypeParameters(f).mapIndexed { idx, it -> extractTypeParameter(it, idx) }
val locId = tw.getLocation(f)
val locId = tw.getLocation(f)
val id =
if (f.isLocalFunction())
getLocallyVisibleFunctionLabels(f).function
else
useFunction<DbCallable>(f, parentId, classTypeArgsIncludingOuterClasses)
val id =
if (f.isLocalFunction())
getLocallyVisibleFunctionLabels(f).function
else
useFunction<DbCallable>(f, parentId, classTypeArgsIncludingOuterClasses)
val sourceDeclaration =
if (typeSubstitution != null)
useFunction(f)
else
id
val sourceDeclaration =
if (typeSubstitution != null)
useFunction(f)
else
id
val extReceiver = f.extensionReceiverParameter
val idxOffset = if (extReceiver != null) 1 else 0
val paramTypes = f.valueParameters.mapIndexed { i, vp ->
extractValueParameter(vp, id, i + idxOffset, typeSubstitution, sourceDeclaration)
}
val allParamTypes = if (extReceiver != null) {
val extendedType = useType(extReceiver.type)
@Suppress("UNCHECKED_CAST")
tw.writeKtExtensionFunctions(id as Label<DbMethod>, extendedType.javaResult.id, extendedType.kotlinResult.id)
val t = extractValueParameter(extReceiver, id, 0, null, sourceDeclaration)
val l = mutableListOf(t)
l.addAll(paramTypes)
l
} else {
paramTypes
}
val paramsSignature = allParamTypes.joinToString(separator = ",", prefix = "(", postfix = ")") { it.javaResult.signature!! }
val substReturnType = typeSubstitution?.let { it(f.returnType, TypeContext.RETURN, pluginContext) } ?: f.returnType
if (f.symbol is IrConstructorSymbol) {
val unitType = useType(pluginContext.irBuiltIns.unitType, TypeContext.RETURN)
val shortName = when {
f.returnType.isAnonymous -> ""
typeSubstitution != null -> useType(substReturnType).javaResult.shortName
else -> f.returnType.classFqName?.shortName()?.asString() ?: f.name.asString()
val extReceiver = f.extensionReceiverParameter
val idxOffset = if (extReceiver != null) 1 else 0
val paramTypes = f.valueParameters.mapIndexed { i, vp ->
extractValueParameter(vp, id, i + idxOffset, typeSubstitution, sourceDeclaration)
}
@Suppress("UNCHECKED_CAST")
tw.writeConstrs(id as Label<DbConstructor>, shortName, "$shortName$paramsSignature", unitType.javaResult.id, unitType.kotlinResult.id, parentId, sourceDeclaration as Label<DbConstructor>)
} else {
val returnType = useType(substReturnType, TypeContext.RETURN)
val shortName = getFunctionShortName(f)
@Suppress("UNCHECKED_CAST")
tw.writeMethods(id as Label<DbMethod>, shortName, "$shortName$paramsSignature", returnType.javaResult.id, returnType.kotlinResult.id, parentId, sourceDeclaration as Label<DbMethod>)
// TODO: fix `sourceId`. It doesn't always match the method ID.
val allParamTypes = if (extReceiver != null) {
val extendedType = useType(extReceiver.type)
@Suppress("UNCHECKED_CAST")
tw.writeKtExtensionFunctions(id as Label<DbMethod>, extendedType.javaResult.id, extendedType.kotlinResult.id)
val t = extractValueParameter(extReceiver, id, 0, null, sourceDeclaration)
val l = mutableListOf(t)
l.addAll(paramTypes)
l
} else {
paramTypes
}
val paramsSignature = allParamTypes.joinToString(separator = ",", prefix = "(", postfix = ")") { it.javaResult.signature!! }
val substReturnType = typeSubstitution?.let { it(f.returnType, TypeContext.RETURN, pluginContext) } ?: f.returnType
if (f.symbol is IrConstructorSymbol) {
val unitType = useType(pluginContext.irBuiltIns.unitType, TypeContext.RETURN)
val shortName = when {
f.returnType.isAnonymous -> ""
typeSubstitution != null -> useType(substReturnType).javaResult.shortName
else -> f.returnType.classFqName?.shortName()?.asString() ?: f.name.asString()
}
@Suppress("UNCHECKED_CAST")
tw.writeConstrs(id as Label<DbConstructor>, shortName, "$shortName$paramsSignature", unitType.javaResult.id, unitType.kotlinResult.id, parentId, sourceDeclaration as Label<DbConstructor>)
} else {
val returnType = useType(substReturnType, TypeContext.RETURN)
val shortName = getFunctionShortName(f)
@Suppress("UNCHECKED_CAST")
tw.writeMethods(id as Label<DbMethod>, shortName, "$shortName$paramsSignature", returnType.javaResult.id, returnType.kotlinResult.id, parentId, sourceDeclaration as Label<DbMethod>)
// TODO: fix `sourceId`. It doesn't always match the method ID.
}
tw.writeHasLocation(id, locId)
val body = f.body
if (body != null && extractBody) {
if (typeSubstitution != null)
logger.warnElement(Severity.ErrorSevere, "Type substitution should only be used to extract a function prototype, not the body", f)
extractBody(body, id)
}
extractVisibility(f, id, f.visibility)
return id
}
tw.writeHasLocation(id, locId)
val body = f.body
if(body != null && extractBody) {
if(typeSubstitution != null)
logger.warnElement(Severity.ErrorSevere, "Type substitution should only be used to extract a function prototype, not the body", f)
extractBody(body, id)
}
extractVisibility(f, id, f.visibility)
declarationStack.pop()
return id
}
fun extractField(f: IrField, parentId: Label<out DbReftype>): Label<out DbField> {
return extractField(useField(f), f.name.asString(), f.type, parentId, tw.getLocation(f), f.visibility, f, isExternalDeclaration(f))
DeclarationStackAdjuster(f).use {
declarationStack.push(f)
return extractField(useField(f), f.name.asString(), f.type, parentId, tw.getLocation(f), f.visibility, f, isExternalDeclaration(f))
}
}
private fun extractField(id: Label<out DbField>, name: String, type: IrType, parentId: Label<out DbReftype>, locId: Label<DbLocation>, visibility: DescriptorVisibility, errorElement: IrElement, isExternalDeclaration: Boolean): Label<out DbField> {
val t = useType(type)
tw.writeFields(id, name, t.javaResult.id, t.kotlinResult.id, parentId, id)
@@ -577,64 +585,68 @@ open class KotlinFileExtractor(
}
fun extractProperty(p: IrProperty, parentId: Label<out DbReftype>, extractBackingField: Boolean, typeSubstitution: TypeSubstitution?, classTypeArgs: List<IrTypeArgument>?) {
DeclarationStackAdjuster(p).use {
val visibility = p.visibility
if (visibility is DelegatedDescriptorVisibility && visibility.delegate == Visibilities.InvisibleFake) {
return
}
val id = useProperty(p, parentId)
val locId = tw.getLocation(p)
tw.writeKtProperties(id, p.name.asString())
tw.writeHasLocation(id, locId)
val bf = p.backingField
val getter = p.getter
val setter = p.setter
if(getter != null) {
@Suppress("UNCHECKED_CAST")
val getterId = extractFunction(getter, parentId, extractBackingField, typeSubstitution, classTypeArgs) as Label<out DbMethod>
tw.writeKtPropertyGetters(id, getterId)
} else {
if (p.modality != Modality.FINAL || !isExternalDeclaration(p)) {
logger.warnElement(Severity.ErrorSevere, "IrProperty without a getter", p)
val visibility = p.visibility
if (visibility is DelegatedDescriptorVisibility && visibility.delegate == Visibilities.InvisibleFake) {
return
}
}
if(setter != null) {
if(!p.isVar) {
logger.warnElement(Severity.ErrorSevere, "!isVar property with a setter", p)
val id = useProperty(p, parentId)
val locId = tw.getLocation(p)
tw.writeKtProperties(id, p.name.asString())
tw.writeHasLocation(id, locId)
val bf = p.backingField
val getter = p.getter
val setter = p.setter
if (getter != null) {
@Suppress("UNCHECKED_CAST")
val getterId = extractFunction(getter, parentId, extractBackingField, typeSubstitution, classTypeArgs) as Label<out DbMethod>
tw.writeKtPropertyGetters(id, getterId)
} else {
if (p.modality != Modality.FINAL || !isExternalDeclaration(p)) {
logger.warnElement(Severity.ErrorSevere, "IrProperty without a getter", p)
}
}
@Suppress("UNCHECKED_CAST")
val setterId = extractFunction(setter, parentId, extractBackingField, typeSubstitution, classTypeArgs) as Label<out DbMethod>
tw.writeKtPropertySetters(id, setterId)
} else {
if (p.isVar && !isExternalDeclaration(p)) {
logger.warnElement(Severity.ErrorSevere, "isVar property without a setter", p)
if (setter != null) {
if (!p.isVar) {
logger.warnElement(Severity.ErrorSevere, "!isVar property with a setter", p)
}
@Suppress("UNCHECKED_CAST")
val setterId = extractFunction(setter, parentId, extractBackingField, typeSubstitution, classTypeArgs) as Label<out DbMethod>
tw.writeKtPropertySetters(id, setterId)
} else {
if (p.isVar && !isExternalDeclaration(p)) {
logger.warnElement(Severity.ErrorSevere, "isVar property without a setter", p)
}
}
}
if(bf != null && extractBackingField) {
val fieldId = extractField(bf, parentId)
tw.writeKtPropertyBackingFields(id, fieldId)
}
if (bf != null && extractBackingField) {
val fieldId = extractField(bf, parentId)
tw.writeKtPropertyBackingFields(id, fieldId)
}
extractVisibility(p, id, p.visibility)
extractVisibility(p, id, p.visibility)
}
}
fun extractEnumEntry(ee: IrEnumEntry, parentId: Label<out DbReftype>) {
val id = useEnumEntry(ee)
val parent = ee.parent
if(parent !is IrClass) {
logger.warnElement(Severity.ErrorSevere, "Enum entry with unexpected parent: " + parent.javaClass, ee)
} else if (parent.typeParameters.isNotEmpty()) {
logger.warnElement(Severity.ErrorSevere, "Enum entry parent class has type parameters: " + parent.name, ee)
} else {
val type = useSimpleTypeClass(parent, emptyList(), false)
tw.writeFields(id, ee.name.asString(), type.javaResult.id, type.kotlinResult.id, parentId, id)
val locId = tw.getLocation(ee)
tw.writeHasLocation(id, locId)
DeclarationStackAdjuster(ee).use {
val id = useEnumEntry(ee)
val parent = ee.parent
if (parent !is IrClass) {
logger.warnElement(Severity.ErrorSevere, "Enum entry with unexpected parent: " + parent.javaClass, ee)
} else if (parent.typeParameters.isNotEmpty()) {
logger.warnElement(Severity.ErrorSevere, "Enum entry parent class has type parameters: " + parent.name, ee)
} else {
val type = useSimpleTypeClass(parent, emptyList(), false)
tw.writeFields(id, ee.name.asString(), type.javaResult.id, type.kotlinResult.id, parentId, id)
val locId = tw.getLocation(ee)
tw.writeHasLocation(id, locId)
}
}
}
@@ -1417,10 +1429,6 @@ open class KotlinFileExtractor(
val stmtParent = parent.stmt(e, callable)
val irCallable = declarationStack.peek()
if (irCallable == null) {
logger.warnElement(Severity.ErrorSevere, "Current function is not set", e)
return
}
val delegatingClass = e.symbol.owner.parent as IrClass
val currentClass = irCallable.parent as IrClass
@@ -1543,10 +1551,6 @@ open class KotlinFileExtractor(
is IrInstanceInitializerCall -> {
val exprParent = parent.expr(e, callable)
val irCallable = declarationStack.peek()
if (irCallable == null) {
logger.warnElement(Severity.ErrorSevere, "Current function is not set", e)
return
}
if (irCallable is IrConstructor && irCallable.isPrimary) {
// Todo add parameter to field assignments
@@ -1741,6 +1745,7 @@ open class KotlinFileExtractor(
tw.writeCallableEnclosingExpr(id, callable)
tw.writeStatementEnclosingExpr(id, exprParent.enclosingStmt)
if (!e.symbol.isBound) {
logger.warnElement(Severity.ErrorSevere, "Unbound enum value", e)
return
}
val owner = e.symbol.owner
@@ -1847,6 +1852,7 @@ open class KotlinFileExtractor(
// field that we are accessing here.
val exprParent = parent.expr(e, callable)
if (!e.symbol.isBound) {
logger.warnElement(Severity.ErrorSevere, "Unbound object value", e)
return
}
@@ -1961,14 +1967,6 @@ open class KotlinFileExtractor(
return
}
if (declarationStack.size == 0) {
// TODO: fix this
logger.warnElement(Severity.ErrorSevere, "Expected to find current declaration", functionReferenceExpr)
return
}
val currentDeclaration = declarationStack.peek()
/*
* Extract generated class:
* ```
@@ -2031,6 +2029,7 @@ open class KotlinFileExtractor(
tw.getFreshIdLabel()
)
val currentDeclaration = declarationStack.peek()
val id = extractGeneratedClass(ids, listOf(pluginContext.irBuiltIns.anyType, fnInterfaceType), locId, currentDeclaration)
fun writeExpressionMetadataToTrapFile(id: Label<out DbExpr>, callable: Label<out DbCallable>, stmt: Label<out DbStmt>) {
@@ -2630,4 +2629,14 @@ open class KotlinFileExtractor(
return id
}
private inner class DeclarationStackAdjuster(declaration: IrDeclaration): Closeable {
init {
declarationStack.push(declaration)
}
override fun close() {
declarationStack.pop()
}
}
}