Extract private members of specialised generic classes on demand

This commit is contained in:
Chris Smowton
2022-10-14 18:45:18 +01:00
parent f1fd470f49
commit 73f5dea51e
4 changed files with 105 additions and 58 deletions

View File

@@ -120,11 +120,7 @@ open class KotlinFileExtractor(
}
private fun shouldExtractDecl(declaration: IrDeclaration, extractPrivateMembers: Boolean) =
extractPrivateMembers ||
when(declaration) {
is IrDeclarationWithVisibility -> declaration.visibility.let { it != DescriptorVisibilities.PRIVATE && it != DescriptorVisibilities.PRIVATE_TO_THIS }
else -> true
}
extractPrivateMembers || !isPrivate(declaration)
fun extractDeclaration(declaration: IrDeclaration, extractPrivateMembers: Boolean, extractFunctionBodies: Boolean) {
with("declaration", declaration) {
@@ -357,23 +353,37 @@ open class KotlinFileExtractor(
}
}
private fun makeTypeParamSubstitution(c: IrClass, argsIncludingOuterClasses: List<IrTypeArgument>?) =
when (argsIncludingOuterClasses) {
null -> { x: IrType, _: TypeContext, _: IrPluginContext -> x.toRawType() }
else -> makeGenericSubstitutionFunction(c, argsIncludingOuterClasses)
}
fun extractDeclarationPrototype(d: IrDeclaration, parentId: Label<out DbReftype>, argsIncludingOuterClasses: List<IrTypeArgument>?, typeParamSubstitutionQ: TypeSubstitution? = null) {
val typeParamSubstitution = typeParamSubstitutionQ ?:
when(val parent = d.parent) {
is IrClass -> makeTypeParamSubstitution(parent, argsIncludingOuterClasses)
else -> {
logger.warnElement("Unable to extract prototype of local declaration", d)
return
}
}
when (d) {
is IrFunction -> extractFunction(d, parentId, extractBody = false, extractMethodAndParameterTypeAccesses = false, typeParamSubstitution, argsIncludingOuterClasses)
is IrProperty -> extractProperty(d, parentId, extractBackingField = false, extractFunctionBodies = false, extractPrivateMembers = false, typeParamSubstitution, argsIncludingOuterClasses)
else -> {}
}
}
// `argsIncludingOuterClasses` can be null to describe a raw generic type.
// For non-generic types it will be zero-length list.
private fun extractNonPrivateMemberPrototypes(c: IrClass, argsIncludingOuterClasses: List<IrTypeArgument>?, id: Label<out DbClassorinterface>) {
with("member prototypes", c) {
val typeParamSubstitution =
when (argsIncludingOuterClasses) {
null -> { x: IrType, _: TypeContext, _: IrPluginContext -> x.toRawType() }
else -> makeGenericSubstitutionFunction(c, argsIncludingOuterClasses)
}
val typeParamSubstitution = makeTypeParamSubstitution(c, argsIncludingOuterClasses)
c.declarations.map {
if (shouldExtractDecl(it, false)) {
when(it) {
is IrFunction -> extractFunction(it, id, extractBody = false, extractMethodAndParameterTypeAccesses = false, typeParamSubstitution, argsIncludingOuterClasses)
is IrProperty -> extractProperty(it, id, extractBackingField = false, extractFunctionBodies = false, extractPrivateMembers = false, typeParamSubstitution, argsIncludingOuterClasses)
else -> {}
}
extractDeclarationPrototype(it, id, argsIncludingOuterClasses, typeParamSubstitution)
}
}
}

View File

@@ -1319,6 +1319,12 @@ open class KotlinUsesExtractor(
}
} ?: f
fun isPrivate(d: IrDeclaration) =
when(d) {
is IrDeclarationWithVisibility -> d.visibility.let { it == DescriptorVisibilities.PRIVATE || it == DescriptorVisibilities.PRIVATE_TO_THIS }
else -> false
}
fun <T: DbCallable> useFunction(f: IrFunction, classTypeArgsIncludingOuterClasses: List<IrTypeArgument>? = null, noReplace: Boolean = false): Label<out T> {
return useFunction(f, null, classTypeArgsIncludingOuterClasses, noReplace)
}
@@ -1330,10 +1336,22 @@ open class KotlinUsesExtractor(
}
val javaFun = kotlinFunctionToJavaEquivalent(f, noReplace)
val label = getFunctionLabel(javaFun, parentId, classTypeArgsIncludingOuterClasses)
val id: Label<T> = tw.getLabelFor(label)
var labelSeenBefore = true
val id: Label<T> = tw.getLabelFor(label) {
labelSeenBefore = false
}
if (isExternalDeclaration(javaFun)) {
extractFunctionLaterIfExternalFileMember(javaFun)
extractExternalEnclosingClassLater(javaFun)
} else if (!labelSeenBefore && classTypeArgsIncludingOuterClasses?.size != 0 && isPrivate(f)) {
// Private function call against a raw or instantiated generic class -- extract the prototype here, since the on-demand route via
// the class label only extracts the public interface. Note guarding this by `labelSeenBefore` is vital because `extractDeclarationPrototype`
// will call this function.
if (this is KotlinFileExtractor) {
useDeclarationParent(f.parent, false, classTypeArgsIncludingOuterClasses, inReceiverContext = true)?.let {
this.extractDeclarationPrototype(f, it.cast(), classTypeArgsIncludingOuterClasses)
}
}
}
return id
}
@@ -1687,7 +1705,18 @@ open class KotlinUsesExtractor(
}
fun useProperty(p: IrProperty, parentId: Label<out DbElement>, classTypeArgsIncludingOuterClasses: List<IrTypeArgument>?): Label<out DbKt_property> =
tw.getLabelFor<DbKt_property>(getPropertyLabel(p, parentId, classTypeArgsIncludingOuterClasses)).also { extractPropertyLaterIfExternalFileMember(p) }
tw.getLabelFor<DbKt_property>(getPropertyLabel(p, parentId, classTypeArgsIncludingOuterClasses)).also {
extractPropertyLaterIfExternalFileMember(p)
if (classTypeArgsIncludingOuterClasses?.size != 0 && isPrivate(p)) {
// Raw or constructed private property usage -- extract the prototype here, since the on-demand route via
// the class label only extracts the public interface.
if (this is KotlinFileExtractor) {
useDeclarationParent(p.parent, false, classTypeArgsIncludingOuterClasses, inReceiverContext = true)?.let {
this.extractDeclarationPrototype(p, it.cast(), classTypeArgsIncludingOuterClasses)
}
}
}
}
fun getEnumEntryLabel(ee: IrEnumEntry): String {
val parentId = useDeclarationParent(ee.parent, false)