[IR] Add body printing strategy to Kotlin-like dumper

This commit is contained in:
Sergej Jaskiewicz
2023-05-01 18:55:42 +02:00
committed by Space Team
parent ca8af7786e
commit 89ff7bd0db
36 changed files with 165 additions and 39 deletions
@@ -64,6 +64,7 @@ class KotlinLikeDumpOptions(
// TODO support // TODO support
val labelPrintingStrategy: LabelPrintingStrategy = LabelPrintingStrategy.NEVER, val labelPrintingStrategy: LabelPrintingStrategy = LabelPrintingStrategy.NEVER,
val printFakeOverridesStrategy: FakeOverridesStrategy = FakeOverridesStrategy.ALL, val printFakeOverridesStrategy: FakeOverridesStrategy = FakeOverridesStrategy.ALL,
val bodyPrintingStrategy: BodyPrintingStrategy = BodyPrintingStrategy.PRINT_BODIES,
val printElseAsTrue: Boolean = false, val printElseAsTrue: Boolean = false,
/* /*
TODO add more options: TODO add more options:
@@ -91,6 +92,12 @@ enum class FakeOverridesStrategy {
NONE NONE
} }
enum class BodyPrintingStrategy {
NO_BODIES,
PRINT_ONLY_LOCAL_CLASSES_AND_FUNCTIONS,
PRINT_BODIES,
}
// TODO_ conventions: // TODO_ conventions:
// TODO support -- for unsupported nodes // TODO support -- for unsupported nodes
// TODO no test -- for the cases with no test(s) // TODO no test -- for the cases with no test(s)
@@ -118,29 +125,33 @@ enum class FakeOverridesStrategy {
*/ */
private class KotlinLikeDumper(val p: Printer, val options: KotlinLikeDumpOptions) : IrElementVisitor<Unit, IrDeclaration?> { private class KotlinLikeDumper(val p: Printer, val options: KotlinLikeDumpOptions) : IrElementVisitor<Unit, IrDeclaration?> {
private val IrSymbol.safeName get() = if (!isBound) { private val IrSymbol.safeName
"/* ERROR: unbound symbol $signature */" get() = if (!isBound) {
} else { "/* ERROR: unbound symbol $signature */"
(owner as? IrDeclarationWithName)?.name?.toString() ?: "/* ERROR: unnamed symbol $signature */" } else {
} (owner as? IrDeclarationWithName)?.name?.toString() ?: "/* ERROR: unnamed symbol $signature */"
}
private val IrFunctionSymbol.safeValueParameters get() = if (!isBound) { private val IrFunctionSymbol.safeValueParameters
emptyList() get() = if (!isBound) {
} else { emptyList()
owner.valueParameters } else {
} owner.valueParameters
}
private val IrSymbol.safeParentClassName get() = if (!isBound) { private val IrSymbol.safeParentClassName
"/* ERROR: unbound symbol $signature */" get() = if (!isBound) {
} else { "/* ERROR: unbound symbol $signature */"
(owner as? IrDeclaration)?.parentClassOrNull?.name?.toString() ?: "/* ERROR: unexpected parent for $safeName */" } else {
} (owner as? IrDeclaration)?.parentClassOrNull?.name?.toString() ?: "/* ERROR: unexpected parent for $safeName */"
}
private val IrSymbol.safeParentClassOrNull get() = if (!isBound) { private val IrSymbol.safeParentClassOrNull
null get() = if (!isBound) {
} else { null
(owner as? IrDeclaration)?.parentClassOrNull } else {
} (owner as? IrDeclaration)?.parentClassOrNull
}
fun printElement(element: IrElement) { fun printElement(element: IrElement) {
@@ -510,8 +521,10 @@ private class KotlinLikeDumper(val p: Printer, val options: KotlinLikeDumpOption
p.printIndent() p.printIndent()
p.printWithNoIndent(declaration.name) p.printWithNoIndent(declaration.name)
declaration.initializerExpression?.let { declaration.initializerExpression?.let {
// it's not valid kotlin if (options.bodyPrintingStrategy == BodyPrintingStrategy.PRINT_BODIES) {
p.printWithNoIndent(" = ") // it's not valid kotlin
p.printWithNoIndent(" = ")
}
it.accept(this, declaration) it.accept(this, declaration)
} }
p.println() p.println()
@@ -528,7 +541,10 @@ private class KotlinLikeDumper(val p: Printer, val options: KotlinLikeDumpOption
// TODO no tests, looks like there are no irText tests for isStatic flag // TODO no tests, looks like there are no irText tests for isStatic flag
p(declaration.isStatic, customModifier("static")) p(declaration.isStatic, customModifier("static"))
p.printWithNoIndent("init ") p.printWithNoIndent("init")
if (options.bodyPrintingStrategy == BodyPrintingStrategy.PRINT_BODIES) {
p.printWithNoIndent(" ")
}
declaration.body.accept(this, declaration) declaration.body.accept(this, declaration)
p.printlnWithNoIndent() p.printlnWithNoIndent()
@@ -582,9 +598,15 @@ private class KotlinLikeDumper(val p: Printer, val options: KotlinLikeDumpOption
declaration.printTypeParametersWithNoIndent() declaration.printTypeParametersWithNoIndent()
declaration.printValueParametersWithNoIndent() declaration.printValueParametersWithNoIndent()
declaration.printWhereClauseIfNeededWithNoIndent() declaration.printWhereClauseIfNeededWithNoIndent()
p.printWithNoIndent(" ") if (declaration.isPrimary) {
p(declaration.isPrimary, customModifier("primary")) p.printWithNoIndent(" ", customModifier("primary"))
declaration.body?.accept(this, declaration) }
declaration.body?.let {
if (options.bodyPrintingStrategy == BodyPrintingStrategy.PRINT_BODIES) {
p.printWithNoIndent(" ")
}
it.accept(this, declaration)
}
p.printlnWithNoIndent() p.printlnWithNoIndent()
} }
@@ -654,10 +676,15 @@ private class KotlinLikeDumper(val p: Printer, val options: KotlinLikeDumpOption
printWhereClauseIfNeededWithNoIndent() printWhereClauseIfNeededWithNoIndent()
body?.let { body?.let {
p.printWithNoIndent(" ") if (options.bodyPrintingStrategy == BodyPrintingStrategy.PRINT_BODIES) {
p.printWithNoIndent(" ")
}
it.accept(this@KotlinLikeDumper, null) it.accept(this@KotlinLikeDumper, null)
} }
} else {
}
if (!printSignatureAndBody || body == null || options.bodyPrintingStrategy != BodyPrintingStrategy.PRINT_BODIES) {
p.printlnWithNoIndent() p.printlnWithNoIndent()
} }
} }
@@ -696,7 +723,9 @@ private class KotlinLikeDumper(val p: Printer, val options: KotlinLikeDumpOption
// TODO print it.type too for varargs? // TODO print it.type too for varargs?
defaultValue?.let { v -> defaultValue?.let { v ->
p.printWithNoIndent(" = ") if (options.bodyPrintingStrategy == BodyPrintingStrategy.PRINT_BODIES) {
p.printWithNoIndent(" = ")
}
v.accept(this@KotlinLikeDumper, data) v.accept(this@KotlinLikeDumper, data)
} }
} }
@@ -781,7 +810,9 @@ private class KotlinLikeDumper(val p: Printer, val options: KotlinLikeDumpOption
* provideDelegate * provideDelegate
*/ */
p(declaration.isDelegated, " " + commentBlock("by")) if (declaration.isDelegated) {
p.printWithNoIndent(" ", commentBlock("by"))
}
p.printlnWithNoIndent() p.printlnWithNoIndent()
p.pushIndent() p.pushIndent()
@@ -789,9 +820,18 @@ private class KotlinLikeDumper(val p: Printer, val options: KotlinLikeDumpOption
// TODO share code with visitField? // TODO share code with visitField?
// it's not valid kotlin // it's not valid kotlin
declaration.backingField?.initializer?.let { declaration.backingField?.initializer?.let {
p.print("field = ") if (options.bodyPrintingStrategy != BodyPrintingStrategy.NO_BODIES) {
// If the strategy is PRINT_ONLY_LOCAL_CLASSES_AND_FUNCTIONS, the local declarations in the backing field initializer
// will be printed under 'field'.
p.print("field")
}
if (options.bodyPrintingStrategy == BodyPrintingStrategy.PRINT_BODIES) {
p.printWithNoIndent(" = ")
}
it.accept(this, declaration) it.accept(this, declaration)
p.printlnWithNoIndent() if (options.bodyPrintingStrategy != BodyPrintingStrategy.NO_BODIES) {
p.printlnWithNoIndent()
}
} }
// TODO generate better name for set parameter `<set-?>`? // TODO generate better name for set parameter `<set-?>`?
@@ -851,7 +891,9 @@ private class KotlinLikeDumper(val p: Printer, val options: KotlinLikeDumpOption
declaration.type.printTypeWithNoIndent() declaration.type.printTypeWithNoIndent()
declaration.initializer?.let { declaration.initializer?.let {
p.printWithNoIndent(" = ") if (options.bodyPrintingStrategy == BodyPrintingStrategy.PRINT_BODIES) {
p.printWithNoIndent(" = ")
}
it.accept(this, declaration) it.accept(this, declaration)
} }
@@ -902,14 +944,49 @@ private class KotlinLikeDumper(val p: Printer, val options: KotlinLikeDumpOption
type.printTypeWithNoIndent() type.printTypeWithNoIndent()
} }
private fun <Body : IrBody> printBody(body: Body, data: IrDeclaration?, actuallyPrint: () -> Unit) {
when (options.bodyPrintingStrategy) {
BodyPrintingStrategy.NO_BODIES -> {}
BodyPrintingStrategy.PRINT_ONLY_LOCAL_CLASSES_AND_FUNCTIONS -> body.acceptChildren(
// Don't print bodies, but print local classes and functions declared in those bodies
object : IrElementVisitor<Unit, IrDeclaration?> {
override fun visitElement(element: IrElement, data: IrDeclaration?) {
element.acceptChildren(this, data)
}
override fun visitDeclaration(declaration: IrDeclarationBase, data: IrDeclaration?) {
p.println()
p.pushIndent()
declaration.accept(this@KotlinLikeDumper, data)
p.popIndent()
}
override fun visitVariable(declaration: IrVariable, data: IrDeclaration?) {
declaration.acceptChildren(this, data)
}
override fun visitLocalDelegatedProperty(declaration: IrLocalDelegatedProperty, data: IrDeclaration?) {
declaration.acceptChildren(this, data)
}
},
data
)
BodyPrintingStrategy.PRINT_BODIES -> actuallyPrint()
}
}
override fun visitExpressionBody(body: IrExpressionBody, data: IrDeclaration?) { override fun visitExpressionBody(body: IrExpressionBody, data: IrDeclaration?) {
// TODO should we print something here? printBody(body, data) {
body.expression.accept(this, data) // TODO should we print something here?
body.expression.accept(this, data)
}
} }
override fun visitBlockBody(body: IrBlockBody, data: IrDeclaration?) { override fun visitBlockBody(body: IrBlockBody, data: IrDeclaration?) {
body.printStatementContainer("{", "}", data) printBody(body, data) {
p.printlnWithNoIndent() body.printStatementContainer("{", "}", data)
p.printlnWithNoIndent()
}
} }
override fun visitComposite(expression: IrComposite, data: IrDeclaration?) { override fun visitComposite(expression: IrComposite, data: IrDeclaration?) {
@@ -950,8 +1027,10 @@ private class KotlinLikeDumper(val p: Printer, val options: KotlinLikeDumpOption
} }
override fun visitSyntheticBody(body: IrSyntheticBody, data: IrDeclaration?) { override fun visitSyntheticBody(body: IrSyntheticBody, data: IrDeclaration?) {
// it's not valid kotlin printBody(body, data) {
p.printlnWithNoIndent("/* Synthetic body for ${body.kind} */") // it's not valid kotlin
p.printlnWithNoIndent("/* Synthetic body for ${body.kind} */")
}
} }
override fun visitCall(expression: IrCall, data: IrDeclaration?) { override fun visitCall(expression: IrCall, data: IrDeclaration?) {
@@ -6,6 +6,7 @@ abstract class AbstractClass {
} }
abstract fun abstractFun() abstract fun abstractFun()
abstract val abstractVal: Int abstract val abstractVal: Int
abstract get abstract get
@@ -17,6 +18,7 @@ abstract class AbstractClass {
interface Interface { interface Interface {
abstract fun abstractFun() abstract fun abstractFun()
abstract val abstractVal: Int abstract val abstractVal: Int
abstract get abstract get
@@ -62,6 +62,7 @@ class C {
interface NestedInterface { interface NestedInterface {
abstract fun foo() abstract fun foo()
fun bar() { fun bar() {
return <this>.foo() return <this>.foo()
} }
@@ -1,5 +1,6 @@
interface IBase<A : Any?> { interface IBase<A : Any?> {
abstract fun <B : Any?> foo(a: A, b: B) abstract fun <B : Any?> foo(a: A, b: B)
abstract val <C : Any?> C.id: Map<A, C>? abstract val <C : Any?> C.id: Map<A, C>?
abstract get abstract get
@@ -1,5 +1,6 @@
interface IBase<A : Any?> { interface IBase<A : Any?> {
abstract fun <B : Any?> foo(a: A, b: B) abstract fun <B : Any?> foo(a: A, b: B)
abstract val <C : Any?> C.id: Map<A, C>? abstract val <C : Any?> C.id: Map<A, C>?
abstract get abstract get
@@ -1,6 +1,8 @@
interface IBase { interface IBase {
abstract fun foo(x: Int, s: String) abstract fun foo(x: Int, s: String)
abstract fun bar(): Int abstract fun bar(): Int
abstract fun String.qux() abstract fun String.qux()
} }
@@ -1,6 +1,8 @@
interface IBase { interface IBase {
abstract fun foo(x: Int, s: String) abstract fun foo(x: Int, s: String)
abstract fun bar(): Int abstract fun bar(): Int
abstract fun String.qux() abstract fun String.qux()
} }
@@ -1,5 +1,6 @@
interface IFooBar { interface IFooBar {
abstract fun foo() abstract fun foo()
abstract fun bar() abstract fun bar()
} }
@@ -1,5 +1,6 @@
interface IFooBar { interface IFooBar {
abstract fun foo() abstract fun foo()
abstract fun bar() abstract fun bar()
} }
+2
View File
@@ -66,6 +66,7 @@ abstract enum class TestEnum3 : Enum<TestEnum3> {
} }
abstract fun foo() abstract fun foo()
fun values(): Array<TestEnum3> /* Synthetic body for ENUM_VALUES */ fun values(): Array<TestEnum3> /* Synthetic body for ENUM_VALUES */
fun valueOf(value: String): TestEnum3 /* Synthetic body for ENUM_VALUEOF */ fun valueOf(value: String): TestEnum3 /* Synthetic body for ENUM_VALUEOF */
@@ -122,6 +123,7 @@ abstract enum class TestEnum4 : Enum<TestEnum4> {
} }
abstract fun foo() abstract fun foo()
fun values(): Array<TestEnum4> /* Synthetic body for ENUM_VALUES */ fun values(): Array<TestEnum4> /* Synthetic body for ENUM_VALUES */
fun valueOf(value: String): TestEnum4 /* Synthetic body for ENUM_VALUEOF */ fun valueOf(value: String): TestEnum4 /* Synthetic body for ENUM_VALUEOF */
@@ -142,6 +142,7 @@ abstract enum class TestAbstractEnum1 : Enum<TestAbstractEnum1> {
} }
abstract fun foo() abstract fun foo()
fun values(): Array<TestAbstractEnum1> /* Synthetic body for ENUM_VALUES */ fun values(): Array<TestAbstractEnum1> /* Synthetic body for ENUM_VALUES */
fun valueOf(value: String): TestAbstractEnum1 /* Synthetic body for ENUM_VALUEOF */ fun valueOf(value: String): TestAbstractEnum1 /* Synthetic body for ENUM_VALUEOF */
@@ -96,6 +96,7 @@ abstract enum class Test2 : Enum<Test2> {
} }
abstract fun foo() abstract fun foo()
fun values(): Array<Test2> /* Synthetic body for ENUM_VALUES */ fun values(): Array<Test2> /* Synthetic body for ENUM_VALUES */
fun valueOf(value: String): Test2 /* Synthetic body for ENUM_VALUEOF */ fun valueOf(value: String): Test2 /* Synthetic body for ENUM_VALUEOF */
@@ -16,6 +16,7 @@ open class Base {
interface BaseI { interface BaseI {
abstract fun foo() abstract fun foo()
abstract val bar: String abstract val bar: String
abstract get abstract get
@@ -14,6 +14,7 @@ interface IFoo {
@Ann @Ann
abstract fun testFun() abstract fun testFun()
@Ann @Ann
abstract val String.testExtVal: String abstract val String.testExtVal: String
abstract get abstract get
@@ -14,6 +14,7 @@ interface IFoo {
@Ann @Ann
abstract fun testFun() abstract fun testFun()
@Ann @Ann
abstract val String.testExtVal: String abstract val String.testExtVal: String
abstract get abstract get
@@ -7,6 +7,7 @@ fun outer() {
} }
abstract fun afun() abstract fun afun()
abstract val aval: Int abstract val aval: Int
abstract get abstract get
@@ -7,6 +7,7 @@ expect abstract class A {
expect open class B : A { expect open class B : A {
expect constructor(i: Int) /* primary */ expect constructor(i: Int) /* primary */
expect override fun foo() expect override fun foo()
expect open fun bar(s: String) expect open fun bar(s: String)
} }
@@ -1,5 +1,6 @@
interface IBase<T : Any?> { interface IBase<T : Any?> {
abstract fun foo(x: Int) abstract fun foo(x: Int)
abstract val bar: Int abstract val bar: Int
abstract get abstract get
@@ -1,5 +1,6 @@
interface IBase<T : Any?> { interface IBase<T : Any?> {
abstract fun foo(x: Int) abstract fun foo(x: Int)
abstract val bar: Int abstract val bar: Int
abstract get abstract get
@@ -1,5 +1,6 @@
interface IFoo { interface IFoo {
abstract fun foo() abstract fun foo()
fun bar() { fun bar() {
<this>.foo() <this>.foo()
} }
@@ -1,5 +1,6 @@
interface Visitor { interface Visitor {
abstract fun visit() abstract fun visit()
fun visitArray(): Visitor? { fun visitArray(): Visitor? {
return null return null
} }
@@ -1,5 +1,6 @@
interface Visitor { interface Visitor {
abstract fun visit() abstract fun visit()
fun visitArray(): Visitor? { fun visitArray(): Visitor? {
return null return null
} }
@@ -9,7 +9,9 @@ sealed class ArrayMap<T : Any> : Iterable<T> {
abstract get abstract get
abstract operator fun set(index: Int, value: T) abstract operator fun set(index: Int, value: T)
abstract operator fun get(index: Int): T? abstract operator fun get(index: Int): T?
abstract fun copy(): ArrayMap<T> abstract fun copy(): ArrayMap<T>
} }
@@ -9,7 +9,9 @@ sealed class ArrayMap<T : Any> : Iterable<T> {
abstract get abstract get
abstract operator fun set(index: Int, value: T) abstract operator fun set(index: Int, value: T)
abstract operator fun get(index: Int): T? abstract operator fun get(index: Int): T?
abstract fun copy(): ArrayMap<T> abstract fun copy(): ArrayMap<T>
} }
@@ -4,7 +4,9 @@ interface IrType {
interface TypeRemapper { interface TypeRemapper {
abstract fun enterScope(irTypeParametersContainer: IrTypeParametersContainer) abstract fun enterScope(irTypeParametersContainer: IrTypeParametersContainer)
abstract fun remapType(type: IrType): IrType abstract fun remapType(type: IrType): IrType
abstract fun leaveScope() abstract fun leaveScope()
} }
@@ -4,7 +4,9 @@ interface IrType {
interface TypeRemapper { interface TypeRemapper {
abstract fun enterScope(irTypeParametersContainer: IrTypeParametersContainer) abstract fun enterScope(irTypeParametersContainer: IrTypeParametersContainer)
abstract fun remapType(type: IrType): IrType abstract fun remapType(type: IrType): IrType
abstract fun leaveScope() abstract fun leaveScope()
} }
@@ -13,6 +13,7 @@ abstract class Base<T : Any?> {
get get
abstract fun <Y : Any?> foo(y: Y): T abstract fun <Y : Any?> foo(y: Y): T
abstract var bar: T abstract var bar: T
abstract get abstract get
abstract set abstract set
@@ -13,6 +13,7 @@ abstract class Base<T : Any?> {
get get
abstract fun <Y : Any?> foo(y: Y): T abstract fun <Y : Any?> foo(y: Y): T
abstract var bar: T abstract var bar: T
abstract get abstract get
abstract set abstract set
@@ -1,5 +1,6 @@
interface B<T1 : Any?> : A<T1> { interface B<T1 : Any?> : A<T1> {
abstract override fun foo(x: T1): T1 abstract override fun foo(x: T1): T1
abstract override fun bar(x: (T1 & Any)): (T1 & Any) abstract override fun bar(x: (T1 & Any)): (T1 & Any)
} }
@@ -1,5 +1,6 @@
interface B<T1 : Any?> : A<T1> { interface B<T1 : Any?> : A<T1> {
abstract override fun foo(x: T1): T1 abstract override fun foo(x: T1): T1
abstract override fun bar(x: (T1 & Any)): (T1 & Any) abstract override fun bar(x: (T1 & Any)): (T1 & Any)
} }
@@ -1,5 +1,6 @@
interface I<T : Any?> { interface I<T : Any?> {
abstract fun input(t: T) abstract fun input(t: T)
abstract fun output(): T abstract fun output(): T
} }
@@ -1,5 +1,6 @@
interface I<T : Any?> { interface I<T : Any?> {
abstract fun input(t: T) abstract fun input(t: T)
abstract fun output(): T abstract fun output(): T
} }
@@ -22,6 +22,7 @@ abstract class Box<T> : IFoo, IBar where T : IFoo, T : IBar {
} }
abstract fun <F> foo(tSerializer: I<F>): I<Box<F>> where F : IFoo, F : IBar abstract fun <F> foo(tSerializer: I<F>): I<Box<F>> where F : IFoo, F : IBar
fun bar(vararg serializers: I<*>): I<*> { fun bar(vararg serializers: I<*>): I<*> {
return <this>.foo<IFoo>(tSerializer = serializers.get(index = 0)) return <this>.foo<IFoo>(tSerializer = serializers.get(index = 0))
} }
@@ -22,6 +22,7 @@ abstract class Box<T> : IFoo, IBar where T : IFoo, T : IBar {
} }
abstract fun <F> foo(tSerializer: I<F>): I<Box<F>> where F : IFoo, F : IBar abstract fun <F> foo(tSerializer: I<F>): I<Box<F>> where F : IFoo, F : IBar
fun bar(vararg serializers: I<*>): I<*> { fun bar(vararg serializers: I<*>): I<*> {
return <this>.foo<IBase>(tSerializer = serializers.get(index = 0)) return <this>.foo<IBase>(tSerializer = serializers.get(index = 0))
} }
@@ -1,7 +1,10 @@
interface K { interface K {
abstract fun kf1(): Collection<out CharSequence> abstract fun kf1(): Collection<out CharSequence>
abstract fun kf2(): Collection<CharSequence> abstract fun kf2(): Collection<CharSequence>
abstract fun kg1(c: Collection<out CharSequence>) abstract fun kg1(c: Collection<out CharSequence>)
abstract fun kg2(c: Collection<CharSequence>) abstract fun kg2(c: Collection<CharSequence>)
} }
@@ -1,7 +1,10 @@
interface K { interface K {
abstract fun kf1(): Collection<out CharSequence> abstract fun kf1(): Collection<out CharSequence>
abstract fun kf2(): Collection<CharSequence> abstract fun kf2(): Collection<CharSequence>
abstract fun kg1(c: Collection<out CharSequence>) abstract fun kg1(c: Collection<out CharSequence>)
abstract fun kg2(c: Collection<CharSequence>) abstract fun kg2(c: Collection<CharSequence>)
} }