Skip to content

Commit 73f5dea

Browse files
committed
Extract private members of specialised generic classes on demand
1 parent f1fd470 commit 73f5dea

File tree

4 files changed

+105
-58
lines changed

4 files changed

+105
-58
lines changed

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

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -120,11 +120,7 @@ open class KotlinFileExtractor(
120120
}
121121

122122
private fun shouldExtractDecl(declaration: IrDeclaration, extractPrivateMembers: Boolean) =
123-
extractPrivateMembers ||
124-
when(declaration) {
125-
is IrDeclarationWithVisibility -> declaration.visibility.let { it != DescriptorVisibilities.PRIVATE && it != DescriptorVisibilities.PRIVATE_TO_THIS }
126-
else -> true
127-
}
123+
extractPrivateMembers || !isPrivate(declaration)
128124

129125
fun extractDeclaration(declaration: IrDeclaration, extractPrivateMembers: Boolean, extractFunctionBodies: Boolean) {
130126
with("declaration", declaration) {
@@ -357,23 +353,37 @@ open class KotlinFileExtractor(
357353
}
358354
}
359355

356+
private fun makeTypeParamSubstitution(c: IrClass, argsIncludingOuterClasses: List<IrTypeArgument>?) =
357+
when (argsIncludingOuterClasses) {
358+
null -> { x: IrType, _: TypeContext, _: IrPluginContext -> x.toRawType() }
359+
else -> makeGenericSubstitutionFunction(c, argsIncludingOuterClasses)
360+
}
361+
362+
fun extractDeclarationPrototype(d: IrDeclaration, parentId: Label<out DbReftype>, argsIncludingOuterClasses: List<IrTypeArgument>?, typeParamSubstitutionQ: TypeSubstitution? = null) {
363+
val typeParamSubstitution = typeParamSubstitutionQ ?:
364+
when(val parent = d.parent) {
365+
is IrClass -> makeTypeParamSubstitution(parent, argsIncludingOuterClasses)
366+
else -> {
367+
logger.warnElement("Unable to extract prototype of local declaration", d)
368+
return
369+
}
370+
}
371+
when (d) {
372+
is IrFunction -> extractFunction(d, parentId, extractBody = false, extractMethodAndParameterTypeAccesses = false, typeParamSubstitution, argsIncludingOuterClasses)
373+
is IrProperty -> extractProperty(d, parentId, extractBackingField = false, extractFunctionBodies = false, extractPrivateMembers = false, typeParamSubstitution, argsIncludingOuterClasses)
374+
else -> {}
375+
}
376+
}
377+
360378
// `argsIncludingOuterClasses` can be null to describe a raw generic type.
361379
// For non-generic types it will be zero-length list.
362380
private fun extractNonPrivateMemberPrototypes(c: IrClass, argsIncludingOuterClasses: List<IrTypeArgument>?, id: Label<out DbClassorinterface>) {
363381
with("member prototypes", c) {
364-
val typeParamSubstitution =
365-
when (argsIncludingOuterClasses) {
366-
null -> { x: IrType, _: TypeContext, _: IrPluginContext -> x.toRawType() }
367-
else -> makeGenericSubstitutionFunction(c, argsIncludingOuterClasses)
368-
}
382+
val typeParamSubstitution = makeTypeParamSubstitution(c, argsIncludingOuterClasses)
369383

370384
c.declarations.map {
371385
if (shouldExtractDecl(it, false)) {
372-
when(it) {
373-
is IrFunction -> extractFunction(it, id, extractBody = false, extractMethodAndParameterTypeAccesses = false, typeParamSubstitution, argsIncludingOuterClasses)
374-
is IrProperty -> extractProperty(it, id, extractBackingField = false, extractFunctionBodies = false, extractPrivateMembers = false, typeParamSubstitution, argsIncludingOuterClasses)
375-
else -> {}
376-
}
386+
extractDeclarationPrototype(it, id, argsIncludingOuterClasses, typeParamSubstitution)
377387
}
378388
}
379389
}

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

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1319,6 +1319,12 @@ open class KotlinUsesExtractor(
13191319
}
13201320
} ?: f
13211321

1322+
fun isPrivate(d: IrDeclaration) =
1323+
when(d) {
1324+
is IrDeclarationWithVisibility -> d.visibility.let { it == DescriptorVisibilities.PRIVATE || it == DescriptorVisibilities.PRIVATE_TO_THIS }
1325+
else -> false
1326+
}
1327+
13221328
fun <T: DbCallable> useFunction(f: IrFunction, classTypeArgsIncludingOuterClasses: List<IrTypeArgument>? = null, noReplace: Boolean = false): Label<out T> {
13231329
return useFunction(f, null, classTypeArgsIncludingOuterClasses, noReplace)
13241330
}
@@ -1330,10 +1336,22 @@ open class KotlinUsesExtractor(
13301336
}
13311337
val javaFun = kotlinFunctionToJavaEquivalent(f, noReplace)
13321338
val label = getFunctionLabel(javaFun, parentId, classTypeArgsIncludingOuterClasses)
1333-
val id: Label<T> = tw.getLabelFor(label)
1339+
var labelSeenBefore = true
1340+
val id: Label<T> = tw.getLabelFor(label) {
1341+
labelSeenBefore = false
1342+
}
13341343
if (isExternalDeclaration(javaFun)) {
13351344
extractFunctionLaterIfExternalFileMember(javaFun)
13361345
extractExternalEnclosingClassLater(javaFun)
1346+
} else if (!labelSeenBefore && classTypeArgsIncludingOuterClasses?.size != 0 && isPrivate(f)) {
1347+
// Private function call against a raw or instantiated generic class -- extract the prototype here, since the on-demand route via
1348+
// the class label only extracts the public interface. Note guarding this by `labelSeenBefore` is vital because `extractDeclarationPrototype`
1349+
// will call this function.
1350+
if (this is KotlinFileExtractor) {
1351+
useDeclarationParent(f.parent, false, classTypeArgsIncludingOuterClasses, inReceiverContext = true)?.let {
1352+
this.extractDeclarationPrototype(f, it.cast(), classTypeArgsIncludingOuterClasses)
1353+
}
1354+
}
13371355
}
13381356
return id
13391357
}
@@ -1687,7 +1705,18 @@ open class KotlinUsesExtractor(
16871705
}
16881706

16891707
fun useProperty(p: IrProperty, parentId: Label<out DbElement>, classTypeArgsIncludingOuterClasses: List<IrTypeArgument>?): Label<out DbKt_property> =
1690-
tw.getLabelFor<DbKt_property>(getPropertyLabel(p, parentId, classTypeArgsIncludingOuterClasses)).also { extractPropertyLaterIfExternalFileMember(p) }
1708+
tw.getLabelFor<DbKt_property>(getPropertyLabel(p, parentId, classTypeArgsIncludingOuterClasses)).also {
1709+
extractPropertyLaterIfExternalFileMember(p)
1710+
if (classTypeArgsIncludingOuterClasses?.size != 0 && isPrivate(p)) {
1711+
// Raw or constructed private property usage -- extract the prototype here, since the on-demand route via
1712+
// the class label only extracts the public interface.
1713+
if (this is KotlinFileExtractor) {
1714+
useDeclarationParent(p.parent, false, classTypeArgsIncludingOuterClasses, inReceiverContext = true)?.let {
1715+
this.extractDeclarationPrototype(p, it.cast(), classTypeArgsIncludingOuterClasses)
1716+
}
1717+
}
1718+
}
1719+
}
16911720

16921721
fun getEnumEntryLabel(ee: IrEnumEntry): String {
16931722
val parentId = useDeclarationParent(ee.parent, false)

0 commit comments

Comments
 (0)