@@ -85,6 +85,10 @@ open class KotlinFileExtractor(
85
85
file.declarations.forEach { extractDeclaration(it, extractPrivateMembers = true , extractFunctionBodies = true ) }
86
86
extractStaticInitializer(file, { extractFileClass(file) })
87
87
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
+ }
88
92
}
89
93
}
90
94
@@ -306,7 +310,7 @@ open class KotlinFileExtractor(
306
310
}
307
311
}.firstOrNull { it != null } ? : false )
308
312
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 ())
310
314
311
315
return id
312
316
}
@@ -415,7 +419,7 @@ open class KotlinFileExtractor(
415
419
val locId = tw.getLocation(c)
416
420
tw.writeHasLocation(id, locId)
417
421
418
- extractEnclosingClass(c, id, locId, listOf ())
422
+ extractEnclosingClass(c.parent , id, c , locId, listOf ())
419
423
420
424
val javaClass = (c.source as ? JavaSourceElement )?.javaElement as ? JavaClass
421
425
@@ -522,10 +526,21 @@ open class KotlinFileExtractor(
522
526
}
523
527
}
524
528
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
529
544
while (parent != null ) {
530
545
if (parent is IrClass ) {
531
546
val parentId =
@@ -535,13 +550,13 @@ open class KotlinFileExtractor(
535
550
useClassInstance(parent, parentClassTypeArguments).typeResult.id
536
551
}
537
552
tw.writeEnclInReftype(innerId, parentId)
538
- if (innerDeclaration is IrClass && innerDeclaration .isCompanion) {
553
+ if (innerClass != null && innerClass .isCompanion) {
539
554
// If we are a companion then our parent has a
540
555
// public static final ParentClass$CompanionObjectClass CompanionObjectName;
541
556
// that we need to fabricate here
542
- val instance = useCompanionObjectClassInstance(innerDeclaration )
557
+ val instance = useCompanionObjectClassInstance(innerClass )
543
558
if (instance != null ) {
544
- val type = useSimpleTypeClass(innerDeclaration , emptyList(), false )
559
+ val type = useSimpleTypeClass(innerClass , emptyList(), false )
545
560
tw.writeFields(instance.id, instance.name, type.javaResult.id, parentId, instance.id)
546
561
tw.writeFieldsKotlinType(instance.id, type.kotlinResult.id)
547
562
tw.writeHasLocation(instance.id, innerLocId)
@@ -552,7 +567,7 @@ open class KotlinFileExtractor(
552
567
553
568
break
554
569
} else if (parent is IrFile ) {
555
- if (innerDeclaration is IrClass ) {
570
+ if (innerClass != null ) {
556
571
// We don't have to extract file class containers for classes
557
572
break
558
573
}
@@ -910,7 +925,6 @@ open class KotlinFileExtractor(
910
925
private fun extractField (f : IrField , parentId : Label <out DbReftype >): Label <out DbField > {
911
926
with (" field" , f) {
912
927
DeclarationStackAdjuster (f).use {
913
- declarationStack.push(f)
914
928
val fNameSuffix = getExtensionReceiverType(f)?.let { it.classFqName?.asString()?.replace(" ." , " $$" ) } ? : " "
915
929
return extractField(useField(f), " ${f.name.asString()}$fNameSuffix " , f.type, parentId, tw.getLocation(f), f.visibility, f, isExternalDeclaration(f), f.isFinal)
916
930
}
@@ -2468,9 +2482,6 @@ open class KotlinFileExtractor(
2468
2482
}
2469
2483
}
2470
2484
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
-
2474
2485
abstract inner class StmtExprParent {
2475
2486
abstract fun stmt (e : IrExpression , callable : Label <out DbCallable >): StmtParent
2476
2487
abstract fun expr (e : IrExpression , callable : Label <out DbCallable >): ExprParent
@@ -3725,12 +3736,12 @@ open class KotlinFileExtractor(
3725
3736
constructorBlock = tw.getFreshIdLabel()
3726
3737
)
3727
3738
3728
- val currentDeclaration = declarationStack.peek()
3739
+ val declarationParent = declarationStack.peekAsDeclarationParent(propertyReferenceExpr) ? : return
3729
3740
val prefix = if (kPropertyClass.owner.name.asString().startsWith(" KMutableProperty" )) " Mutable" else " "
3730
3741
val baseClass = pluginContext.referenceClass(FqName (" kotlin.jvm.internal.${prefix} PropertyReference${kPropertyType.arguments.size - 1 } " ))?.owner?.typeWith()
3731
3742
? : pluginContext.irBuiltIns.anyType
3732
3743
3733
- val classId = extractGeneratedClass(ids, listOf (baseClass, kPropertyType), locId, currentDeclaration )
3744
+ val classId = extractGeneratedClass(ids, listOf (baseClass, kPropertyType), locId, propertyReferenceExpr, declarationParent )
3734
3745
3735
3746
val helper = PropertyReferenceHelper (propertyReferenceExpr, locId, ids)
3736
3747
@@ -3932,12 +3943,12 @@ open class KotlinFileExtractor(
3932
3943
if (fnInterfaceType == null ) {
3933
3944
logger.warnElement(" Cannot find functional interface type for function reference" , functionReferenceExpr)
3934
3945
} else {
3935
- val currentDeclaration = declarationStack.peek()
3946
+ val declarationParent = declarationStack.peekAsDeclarationParent(functionReferenceExpr) ? : return
3936
3947
// `FunctionReference` base class is required, because that's implementing `KFunction`.
3937
3948
val baseClass = pluginContext.referenceClass(FqName (" kotlin.jvm.internal.FunctionReference" ))?.owner?.typeWith()
3938
3949
? : pluginContext.irBuiltIns.anyType
3939
3950
3940
- val classId = extractGeneratedClass(ids, listOf (baseClass, fnInterfaceType), locId, currentDeclaration )
3951
+ val classId = extractGeneratedClass(ids, listOf (baseClass, fnInterfaceType), locId, functionReferenceExpr, declarationParent )
3941
3952
3942
3953
helper.extractReceiverField()
3943
3954
@@ -4541,8 +4552,8 @@ open class KotlinFileExtractor(
4541
4552
val locId = tw.getLocation(e)
4542
4553
val helper = GeneratedClassHelper (locId, ids)
4543
4554
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 )
4546
4557
4547
4558
// add field
4548
4559
val fieldId = tw.getFreshIdLabel<DbField >()
@@ -4684,7 +4695,8 @@ open class KotlinFileExtractor(
4684
4695
ids : GeneratedClassLabels ,
4685
4696
superTypes : List <IrType >,
4686
4697
locId : Label <DbLocation >,
4687
- currentDeclaration : IrDeclaration
4698
+ elementToReportOn : IrElement ,
4699
+ declarationParent : IrDeclarationParent
4688
4700
): Label <out DbClass > {
4689
4701
// Write class
4690
4702
val id = ids.type.javaResult.id.cast<DbClass >()
@@ -4707,11 +4719,11 @@ open class KotlinFileExtractor(
4707
4719
// Super call
4708
4720
val baseClass = superTypes.first().classOrNull
4709
4721
if (baseClass == null ) {
4710
- logger.warnElement(" Cannot find base class" , currentDeclaration )
4722
+ logger.warnElement(" Cannot find base class" , elementToReportOn )
4711
4723
} else {
4712
4724
val baseConstructor = baseClass.owner.declarations.findSubType<IrFunction > { it.symbol is IrConstructorSymbol }
4713
4725
if (baseConstructor == null ) {
4714
- logger.warnElement(" Cannot find base constructor" , currentDeclaration )
4726
+ logger.warnElement(" Cannot find base constructor" , elementToReportOn )
4715
4727
} else {
4716
4728
val superCallId = tw.getFreshIdLabel<DbSuperconstructorinvocationstmt >()
4717
4729
tw.writeStmts_superconstructorinvocationstmt(superCallId, constructorBlockId, 0 , ids.constructor )
@@ -4727,7 +4739,7 @@ open class KotlinFileExtractor(
4727
4739
addVisibilityModifierToLocalOrAnonymousClass(id)
4728
4740
extractClassSupertypes(superTypes, listOf (), id, inReceiverContext = true )
4729
4741
4730
- extractEnclosingClass(currentDeclaration , id, locId, listOf ())
4742
+ extractEnclosingClass(declarationParent , id, null , locId, listOf ())
4731
4743
4732
4744
return id
4733
4745
}
@@ -4739,7 +4751,7 @@ open class KotlinFileExtractor(
4739
4751
with (" generated class" , localFunction) {
4740
4752
val ids = getLocallyVisibleFunctionLabels(localFunction)
4741
4753
4742
- val id = extractGeneratedClass(ids, superTypes, tw.getLocation(localFunction), localFunction)
4754
+ val id = extractGeneratedClass(ids, superTypes, tw.getLocation(localFunction), localFunction, localFunction.parent )
4743
4755
4744
4756
// Extract local function as a member
4745
4757
extractFunction(localFunction, id, extractBody = true , extractMethodAndParameterTypeAccesses = true , null , listOf ())
@@ -4748,6 +4760,34 @@ open class KotlinFileExtractor(
4748
4760
}
4749
4761
}
4750
4762
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
+ }
4751
4791
4752
4792
private inner class DeclarationStackAdjuster (declaration : IrDeclaration ): Closeable {
4753
4793
init {
0 commit comments