Skip to content

Commit b3a97f7

Browse files
committed
Merge branch 'main' into download-db-vs-code
2 parents 356ca78 + c7e3051 commit b3a97f7

File tree

5 files changed

+76
-26
lines changed

5 files changed

+76
-26
lines changed

java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt

Lines changed: 65 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -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 {

java/kotlin-extractor/src/main/kotlin/TrapWriter.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ class SourceFileTrapWriter (
319319
lm: TrapLabelManager,
320320
bw: BufferedWriter,
321321
diagnosticTrapWriter: TrapWriter?,
322-
irFile: IrFile,
322+
val irFile: IrFile,
323323
populateFileTables: Boolean) :
324324
FileTrapWriter(loggerBase, lm, bw, diagnosticTrapWriter, irFile.path, populateFileTables) {
325325

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
abstract class Base(func:() -> Unit = {}) { }
2+
3+
class Derived : Base({
4+
data class Dc(val foo: String)
5+
})

java/ql/test/kotlin/library-tests/declaration-stack/test.expected

Whitespace-only changes.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import java
2+
import semmle.code.java.Diagnostics
3+
4+
from Diagnostic d
5+
select d

0 commit comments

Comments
 (0)