@@ -85,6 +85,10 @@ open class KotlinFileExtractor(
8585 file.declarations.forEach { extractDeclaration(it, extractPrivateMembers = true , extractFunctionBodies = true ) }
8686 extractStaticInitializer(file, { extractFileClass(file) })
8787 CommentExtractor (this , file, tw.fileId).extract()
88+
89+ if (! declarationStack.isEmpty()) {
90+ logger.errorElement(" Declaration stack is not empty after processing the file" , file)
91+ }
8892 }
8993 }
9094
@@ -306,7 +310,7 @@ open class KotlinFileExtractor(
306310 }
307311 }.firstOrNull { it != null } ? : false )
308312
309- extractEnclosingClass(c, id, locId, if (useBoundOuterType) argsIncludingOuterClasses?.drop(c.typeParameters.size) else listOf ())
313+ extractEnclosingClass(c.parent , id, c , locId, if (useBoundOuterType) argsIncludingOuterClasses?.drop(c.typeParameters.size) else listOf ())
310314
311315 return id
312316 }
@@ -415,7 +419,7 @@ open class KotlinFileExtractor(
415419 val locId = tw.getLocation(c)
416420 tw.writeHasLocation(id, locId)
417421
418- extractEnclosingClass(c, id, locId, listOf ())
422+ extractEnclosingClass(c.parent , id, c , locId, listOf ())
419423
420424 val javaClass = (c.source as ? JavaSourceElement )?.javaElement as ? JavaClass
421425
@@ -522,10 +526,21 @@ open class KotlinFileExtractor(
522526 }
523527 }
524528
525- // If `parentClassTypeArguments` is null, the parent class is a raw type.
526- private fun extractEnclosingClass (innerDeclaration : IrDeclaration , innerId : Label <out DbClassorinterface >, innerLocId : Label <DbLocation >, parentClassTypeArguments : List <IrTypeArgument >? ) {
527- with (" enclosing class" , innerDeclaration) {
528- var parent: IrDeclarationParent ? = innerDeclaration.parent
529+ /* *
530+ * This function traverses the declaration-parent hierarchy upwards, and retrieves the enclosing class of a class to extract the `enclInReftype` relation.
531+ * Additionally, it extracts a companion field for a companion object into its parent class.
532+ *
533+ * Note that the nested class can also be a local class declared inside a function, so the upwards traversal is skipping the non-class parents. Also, in some cases the file class is the enclosing one, which has no IR representation.
534+ */
535+ private fun extractEnclosingClass (
536+ declarationParent : IrDeclarationParent , // The declaration parent of the element for which we are extracting the enclosing class
537+ innerId : Label <out DbClassorinterface >, // ID of the inner class
538+ innerClass : IrClass ? , // The inner class, if available. It's not available if the enclosing class of a generated class is being extracted
539+ innerLocId : Label <DbLocation >, // Location of the inner class
540+ parentClassTypeArguments : List <IrTypeArgument >? // Type arguments of the parent class. If `parentClassTypeArguments` is null, the parent class is a raw type
541+ ) {
542+ with (" enclosing class" , declarationParent) {
543+ var parent: IrDeclarationParent ? = declarationParent
529544 while (parent != null ) {
530545 if (parent is IrClass ) {
531546 val parentId =
@@ -535,13 +550,13 @@ open class KotlinFileExtractor(
535550 useClassInstance(parent, parentClassTypeArguments).typeResult.id
536551 }
537552 tw.writeEnclInReftype(innerId, parentId)
538- if (innerDeclaration is IrClass && innerDeclaration .isCompanion) {
553+ if (innerClass != null && innerClass .isCompanion) {
539554 // If we are a companion then our parent has a
540555 // public static final ParentClass$CompanionObjectClass CompanionObjectName;
541556 // that we need to fabricate here
542- val instance = useCompanionObjectClassInstance(innerDeclaration )
557+ val instance = useCompanionObjectClassInstance(innerClass )
543558 if (instance != null ) {
544- val type = useSimpleTypeClass(innerDeclaration , emptyList(), false )
559+ val type = useSimpleTypeClass(innerClass , emptyList(), false )
545560 tw.writeFields(instance.id, instance.name, type.javaResult.id, parentId, instance.id)
546561 tw.writeFieldsKotlinType(instance.id, type.kotlinResult.id)
547562 tw.writeHasLocation(instance.id, innerLocId)
@@ -552,7 +567,7 @@ open class KotlinFileExtractor(
552567
553568 break
554569 } else if (parent is IrFile ) {
555- if (innerDeclaration is IrClass ) {
570+ if (innerClass != null ) {
556571 // We don't have to extract file class containers for classes
557572 break
558573 }
@@ -910,7 +925,6 @@ open class KotlinFileExtractor(
910925 private fun extractField (f : IrField , parentId : Label <out DbReftype >): Label <out DbField > {
911926 with (" field" , f) {
912927 DeclarationStackAdjuster (f).use {
913- declarationStack.push(f)
914928 val fNameSuffix = getExtensionReceiverType(f)?.let { it.classFqName?.asString()?.replace(" ." , " $$" ) } ? : " "
915929 return extractField(useField(f), " ${f.name.asString()}$fNameSuffix " , f.type, parentId, tw.getLocation(f), f.visibility, f, isExternalDeclaration(f), f.isFinal)
916930 }
@@ -2468,9 +2482,6 @@ open class KotlinFileExtractor(
24682482 }
24692483 }
24702484
2471- // todo: calculating the enclosing ref type could be done through this, instead of walking up the declaration parent chain
2472- private val declarationStack: Stack <IrDeclaration > = Stack ()
2473-
24742485 abstract inner class StmtExprParent {
24752486 abstract fun stmt (e : IrExpression , callable : Label <out DbCallable >): StmtParent
24762487 abstract fun expr (e : IrExpression , callable : Label <out DbCallable >): ExprParent
@@ -3725,12 +3736,12 @@ open class KotlinFileExtractor(
37253736 constructorBlock = tw.getFreshIdLabel()
37263737 )
37273738
3728- val currentDeclaration = declarationStack.peek()
3739+ val declarationParent = declarationStack.peekAsDeclarationParent(propertyReferenceExpr) ? : return
37293740 val prefix = if (kPropertyClass.owner.name.asString().startsWith(" KMutableProperty" )) " Mutable" else " "
37303741 val baseClass = pluginContext.referenceClass(FqName (" kotlin.jvm.internal.${prefix} PropertyReference${kPropertyType.arguments.size - 1 } " ))?.owner?.typeWith()
37313742 ? : pluginContext.irBuiltIns.anyType
37323743
3733- val classId = extractGeneratedClass(ids, listOf (baseClass, kPropertyType), locId, currentDeclaration )
3744+ val classId = extractGeneratedClass(ids, listOf (baseClass, kPropertyType), locId, propertyReferenceExpr, declarationParent )
37343745
37353746 val helper = PropertyReferenceHelper (propertyReferenceExpr, locId, ids)
37363747
@@ -3932,12 +3943,12 @@ open class KotlinFileExtractor(
39323943 if (fnInterfaceType == null ) {
39333944 logger.warnElement(" Cannot find functional interface type for function reference" , functionReferenceExpr)
39343945 } else {
3935- val currentDeclaration = declarationStack.peek()
3946+ val declarationParent = declarationStack.peekAsDeclarationParent(functionReferenceExpr) ? : return
39363947 // `FunctionReference` base class is required, because that's implementing `KFunction`.
39373948 val baseClass = pluginContext.referenceClass(FqName (" kotlin.jvm.internal.FunctionReference" ))?.owner?.typeWith()
39383949 ? : pluginContext.irBuiltIns.anyType
39393950
3940- val classId = extractGeneratedClass(ids, listOf (baseClass, fnInterfaceType), locId, currentDeclaration )
3951+ val classId = extractGeneratedClass(ids, listOf (baseClass, fnInterfaceType), locId, functionReferenceExpr, declarationParent )
39413952
39423953 helper.extractReceiverField()
39433954
@@ -4541,8 +4552,8 @@ open class KotlinFileExtractor(
45414552 val locId = tw.getLocation(e)
45424553 val helper = GeneratedClassHelper (locId, ids)
45434554
4544- val currentDeclaration = declarationStack.peek()
4545- val classId = extractGeneratedClass(ids, listOf (pluginContext.irBuiltIns.anyType, e.typeOperand), locId, currentDeclaration )
4555+ val declarationParent = declarationStack.peekAsDeclarationParent(e) ? : return
4556+ val classId = extractGeneratedClass(ids, listOf (pluginContext.irBuiltIns.anyType, e.typeOperand), locId, e, declarationParent )
45464557
45474558 // add field
45484559 val fieldId = tw.getFreshIdLabel<DbField >()
@@ -4684,7 +4695,8 @@ open class KotlinFileExtractor(
46844695 ids : GeneratedClassLabels ,
46854696 superTypes : List <IrType >,
46864697 locId : Label <DbLocation >,
4687- currentDeclaration : IrDeclaration
4698+ elementToReportOn : IrElement ,
4699+ declarationParent : IrDeclarationParent
46884700 ): Label <out DbClass > {
46894701 // Write class
46904702 val id = ids.type.javaResult.id.cast<DbClass >()
@@ -4707,11 +4719,11 @@ open class KotlinFileExtractor(
47074719 // Super call
47084720 val baseClass = superTypes.first().classOrNull
47094721 if (baseClass == null ) {
4710- logger.warnElement(" Cannot find base class" , currentDeclaration )
4722+ logger.warnElement(" Cannot find base class" , elementToReportOn )
47114723 } else {
47124724 val baseConstructor = baseClass.owner.declarations.findSubType<IrFunction > { it.symbol is IrConstructorSymbol }
47134725 if (baseConstructor == null ) {
4714- logger.warnElement(" Cannot find base constructor" , currentDeclaration )
4726+ logger.warnElement(" Cannot find base constructor" , elementToReportOn )
47154727 } else {
47164728 val superCallId = tw.getFreshIdLabel<DbSuperconstructorinvocationstmt >()
47174729 tw.writeStmts_superconstructorinvocationstmt(superCallId, constructorBlockId, 0 , ids.constructor )
@@ -4727,7 +4739,7 @@ open class KotlinFileExtractor(
47274739 addVisibilityModifierToLocalOrAnonymousClass(id)
47284740 extractClassSupertypes(superTypes, listOf (), id, inReceiverContext = true )
47294741
4730- extractEnclosingClass(currentDeclaration , id, locId, listOf ())
4742+ extractEnclosingClass(declarationParent , id, null , locId, listOf ())
47314743
47324744 return id
47334745 }
@@ -4739,7 +4751,7 @@ open class KotlinFileExtractor(
47394751 with (" generated class" , localFunction) {
47404752 val ids = getLocallyVisibleFunctionLabels(localFunction)
47414753
4742- val id = extractGeneratedClass(ids, superTypes, tw.getLocation(localFunction), localFunction)
4754+ val id = extractGeneratedClass(ids, superTypes, tw.getLocation(localFunction), localFunction, localFunction.parent )
47434755
47444756 // Extract local function as a member
47454757 extractFunction(localFunction, id, extractBody = true , extractMethodAndParameterTypeAccesses = true , null , listOf ())
@@ -4748,6 +4760,34 @@ open class KotlinFileExtractor(
47484760 }
47494761 }
47504762
4763+ // todo: calculating the enclosing ref type could be done through this, instead of walking up the declaration parent chain
4764+ private val declarationStack = DeclarationStack ()
4765+
4766+ private inner class DeclarationStack {
4767+ private val stack: Stack <IrDeclaration > = Stack ()
4768+
4769+ fun push (item : IrDeclaration ) = stack.push(item)
4770+
4771+ fun pop () = stack.pop()
4772+
4773+ fun isEmpty () = stack.isEmpty()
4774+
4775+ fun peek () = stack.peek()
4776+
4777+ fun peekAsDeclarationParent (elementToReportOn : IrElement ): IrDeclarationParent ? {
4778+ val trapWriter = tw
4779+ if (isEmpty() && trapWriter is SourceFileTrapWriter ) {
4780+ // If the current declaration is used as a parent, we might end up with an empty stack. In this case, the source file is the parent.
4781+ return trapWriter.irFile
4782+ }
4783+
4784+ val dp = peek() as ? IrDeclarationParent
4785+ if (dp == null ) {
4786+ logger.errorElement(" Couldn't find current declaration parent" , elementToReportOn)
4787+ }
4788+ return dp
4789+ }
4790+ }
47514791
47524792 private inner class DeclarationStackAdjuster (declaration : IrDeclaration ): Closeable {
47534793 init {
0 commit comments