Skip to content

Commit d0e521e

Browse files
authored
Merge pull request #9681 from smowton/smowton/fix/reintroduce-obinit
Kotlin: reintroduce obinit when we have multiple secondary constructors and no primary
2 parents fcc8691 + a124d83 commit d0e521e

File tree

5 files changed

+82
-3
lines changed

5 files changed

+82
-3
lines changed

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

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,27 @@ open class KotlinFileExtractor(
371371
tw.writeHasLocation(stmtId, locId)
372372
}
373373

374+
fun extractObinitFunction(c: IrClass, parentId: Label<out DbClassorinterface>) {
375+
// add method:
376+
val obinitLabel = getObinitLabel(c)
377+
val obinitId = tw.getLabelFor<DbMethod>(obinitLabel)
378+
val returnType = useType(pluginContext.irBuiltIns.unitType, TypeContext.RETURN)
379+
tw.writeMethods(obinitId, "<obinit>", "<obinit>()", returnType.javaResult.id, parentId, obinitId)
380+
tw.writeMethodsKotlinType(obinitId, returnType.kotlinResult.id)
381+
382+
val locId = tw.getLocation(c)
383+
tw.writeHasLocation(obinitId, locId)
384+
385+
addModifiers(obinitId, "private")
386+
387+
// add body:
388+
val blockId = tw.getFreshIdLabel<DbBlock>()
389+
tw.writeStmts_block(blockId, obinitId, 0, obinitId)
390+
tw.writeHasLocation(blockId, locId)
391+
392+
extractDeclInitializers(c.declarations, false) { Pair(blockId, obinitId) }
393+
}
394+
374395
fun extractClassSource(c: IrClass, extractDeclarations: Boolean, extractStaticInitializer: Boolean, extractPrivateMembers: Boolean, extractFunctionBodies: Boolean): Label<out DbClassorinterface> {
375396
with("class source", c) {
376397
DeclarationStackAdjuster(c).use {
@@ -425,6 +446,9 @@ open class KotlinFileExtractor(
425446
addModifiers(instance.id, "public", "static", "final")
426447
tw.writeClass_object(id.cast<DbClass>(), instance.id)
427448
}
449+
if (extractFunctionBodies && needsObinitFunction(c)) {
450+
extractObinitFunction(c, id)
451+
}
428452

429453
extractClassModifiers(c, id)
430454
extractClassSupertypes(c, id, inReceiverContext = true) // inReceiverContext = true is specified to force extraction of member prototypes of base types
@@ -2105,6 +2129,22 @@ open class KotlinFileExtractor(
21052129
enclosingStmt: Label<out DbStmt>
21062130
): Label<DbNewexpr> = extractNewExpr(useFunction<DbConstructor>(calledConstructor, constructorTypeArgs), constructedType, locId, parent, idx, callable, enclosingStmt)
21072131

2132+
private fun needsObinitFunction(c: IrClass) = c.primaryConstructor == null && c.constructors.count() > 1
2133+
2134+
private fun getObinitLabel(c: IrClass) = getFunctionLabel(
2135+
c,
2136+
null,
2137+
"<obinit>",
2138+
listOf(),
2139+
pluginContext.irBuiltIns.unitType,
2140+
null,
2141+
functionTypeParameters = listOf(),
2142+
classTypeArgsIncludingOuterClasses = listOf(),
2143+
overridesCollectionsMethod = false,
2144+
javaSignature = null,
2145+
addParameterWildcardsByDefault = false
2146+
)
2147+
21082148
private fun extractConstructorCall(
21092149
e: IrFunctionAccessExpression,
21102150
parent: Label<out DbExprparent>,
@@ -2434,13 +2474,29 @@ open class KotlinFileExtractor(
24342474
loopIdMap.remove(e)
24352475
}
24362476
is IrInstanceInitializerCall -> {
2437-
val stmtParent = parent.stmt(e, callable)
24382477
val irConstructor = declarationStack.peek() as? IrConstructor
24392478
if (irConstructor == null) {
24402479
logger.errorElement("IrInstanceInitializerCall outside constructor", e)
24412480
return
24422481
}
2443-
extractInstanceInitializerBlock(stmtParent, irConstructor)
2482+
if (needsObinitFunction(irConstructor.parentAsClass)) {
2483+
val exprParent = parent.expr(e, callable)
2484+
val id = tw.getFreshIdLabel<DbMethodaccess>()
2485+
val type = useType(pluginContext.irBuiltIns.unitType)
2486+
val locId = tw.getLocation(e)
2487+
val methodLabel = getObinitLabel(irConstructor.parentAsClass)
2488+
val methodId = tw.getLabelFor<DbMethod>(methodLabel)
2489+
tw.writeExprs_methodaccess(id, type.javaResult.id, exprParent.parent, exprParent.idx)
2490+
tw.writeExprsKotlinType(id, type.kotlinResult.id)
2491+
tw.writeHasLocation(id, locId)
2492+
tw.writeCallableEnclosingExpr(id, callable)
2493+
tw.writeStatementEnclosingExpr(id, exprParent.enclosingStmt)
2494+
tw.writeCallableBinding(id, methodId)
2495+
}
2496+
else {
2497+
val stmtParent = parent.stmt(e, callable)
2498+
extractInstanceInitializerBlock(stmtParent, irConstructor)
2499+
}
24442500
}
24452501
is IrConstructorCall -> {
24462502
val exprParent = parent.expr(e, callable)

java/ql/consistency-queries/calls.ql

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
import java
22

33
from MethodAccess ma
4-
where not exists(ma.getQualifier()) and ma.getFile().isKotlinSourceFile()
4+
// Generally Kotlin calls will always use an explicit qualifier, except for calls
5+
// to the synthetic instance initializer <obinit>, which use an implicit `this`.
6+
where
7+
not exists(ma.getQualifier()) and
8+
ma.getFile().isKotlinSourceFile() and
9+
not ma.getCallee() instanceof InstanceInitializer
510
select ma
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
| test.kt:3:20:3:32 | new KProperty1<Test,Integer>(...) { ... } | test.kt:3:20:3:32 | ...::... |
2+
| test.kt:3:28:3:32 | new Function0<Integer>(...) { ... } | test.kt:3:28:3:32 | ...->... |
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
public class Test {
2+
3+
val lazyVal: Int by lazy { 5 }
4+
5+
// Both of these constructors will need to extract the implicit classes created by `lazyVal` and initialize it--
6+
// This test checks we don't introduce any inconsistency this way.
7+
8+
constructor(x: Int) { }
9+
10+
constructor(y: String) { }
11+
12+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import java
2+
3+
from AnonymousClass ac
4+
select ac, ac.getClassInstanceExpr()

0 commit comments

Comments
 (0)