mirror of
https://github.com/apple/pkl.git
synced 2026-04-22 08:18:32 +02:00
codegen-kotlin: Fix generation of copy() methods (#705)
- don't generate copy methods for abstract classes - precisely determine if copy method needs override modifier (tricky) Fixes #569
This commit is contained in:
@@ -274,9 +274,20 @@ class KotlinCodeGenerator(
|
|||||||
return methodBuilder.addCode(codeBuilder.build()).build()
|
return methodBuilder.addCode(codeBuilder.build()).build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun inheritsCopyMethodWithSameArity(): Boolean {
|
||||||
|
val nearestNonAbstractAncestor =
|
||||||
|
generateSequence(pClass.superclass) { it.superclass }.firstOrNull { !it.isAbstract }
|
||||||
|
?: return false
|
||||||
|
return nearestNonAbstractAncestor.allProperties.values.count { !it.isHidden } ==
|
||||||
|
allProperties.size
|
||||||
|
}
|
||||||
|
|
||||||
// besides generating copy method for current class,
|
// besides generating copy method for current class,
|
||||||
// override copy methods inherited from parent classes
|
// override copy methods inherited from parent classes
|
||||||
fun generateCopyMethods(typeBuilder: TypeSpec.Builder) {
|
fun generateCopyMethods(typeBuilder: TypeSpec.Builder) {
|
||||||
|
// copy methods don't make sense for abstract classes
|
||||||
|
if (pClass.isAbstract) return
|
||||||
|
|
||||||
var prevParameterCount = Int.MAX_VALUE
|
var prevParameterCount = Int.MAX_VALUE
|
||||||
for (currClass in generateSequence(pClass) { it.superclass }) {
|
for (currClass in generateSequence(pClass) { it.superclass }) {
|
||||||
if (currClass.isAbstract) continue
|
if (currClass.isAbstract) continue
|
||||||
@@ -285,7 +296,7 @@ class KotlinCodeGenerator(
|
|||||||
|
|
||||||
// avoid generating multiple methods with same no. of parameters
|
// avoid generating multiple methods with same no. of parameters
|
||||||
if (currParameters.size < prevParameterCount) {
|
if (currParameters.size < prevParameterCount) {
|
||||||
val isOverride = currClass !== pClass || superclass != null && properties.isEmpty()
|
val isOverride = currClass !== pClass || inheritsCopyMethodWithSameArity()
|
||||||
typeBuilder.addFunction(generateCopyMethod(currParameters, isOverride))
|
typeBuilder.addFunction(generateCopyMethod(currParameters, isOverride))
|
||||||
prevParameterCount = currParameters.size
|
prevParameterCount = currParameters.size
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -661,6 +661,211 @@ class KotlinCodeGeneratorTest {
|
|||||||
assertCompilesSuccessfully(kotlinCode)
|
assertCompilesSuccessfully(kotlinCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://github.com/apple/pkl/issues/569
|
||||||
|
@Test
|
||||||
|
fun `abstract classes`() {
|
||||||
|
val kotlinCode =
|
||||||
|
generateKotlinCode(
|
||||||
|
"""
|
||||||
|
module my.mod
|
||||||
|
|
||||||
|
abstract class Foo { one: Int }
|
||||||
|
abstract class Bar extends Foo { two: String }
|
||||||
|
class Baz extends Bar { three: Duration }
|
||||||
|
class Qux extends Bar {}
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
assertContains(
|
||||||
|
"""
|
||||||
|
| abstract class Foo(
|
||||||
|
| open val one: Long
|
||||||
|
| ) {
|
||||||
|
"""
|
||||||
|
.trimMargin(),
|
||||||
|
kotlinCode
|
||||||
|
)
|
||||||
|
|
||||||
|
assertContains(
|
||||||
|
"""
|
||||||
|
| abstract class Bar(
|
||||||
|
| one: Long,
|
||||||
|
| open val two: String
|
||||||
|
| ) : Foo(one) {
|
||||||
|
"""
|
||||||
|
.trimMargin(),
|
||||||
|
kotlinCode
|
||||||
|
)
|
||||||
|
|
||||||
|
assertContains(
|
||||||
|
"""
|
||||||
|
| class Baz(
|
||||||
|
| one: Long,
|
||||||
|
| two: String,
|
||||||
|
| val three: Duration
|
||||||
|
| ) : Bar(one, two) {
|
||||||
|
| fun copy(
|
||||||
|
| one: Long = this.one,
|
||||||
|
| two: String = this.two,
|
||||||
|
| three: Duration = this.three
|
||||||
|
| ): Baz = Baz(one, two, three)
|
||||||
|
"""
|
||||||
|
.trimMargin(),
|
||||||
|
kotlinCode
|
||||||
|
)
|
||||||
|
|
||||||
|
assertContains(
|
||||||
|
"""
|
||||||
|
| class Qux(
|
||||||
|
| one: Long,
|
||||||
|
| two: String
|
||||||
|
| ) : Bar(one, two) {
|
||||||
|
| fun copy(one: Long = this.one, two: String = this.two): Qux = Qux(one, two)
|
||||||
|
"""
|
||||||
|
.trimMargin(),
|
||||||
|
kotlinCode
|
||||||
|
)
|
||||||
|
|
||||||
|
assertCompilesSuccessfully(kotlinCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://github.com/apple/pkl/issues/569
|
||||||
|
@Test
|
||||||
|
fun `abstract class that extends open class`() {
|
||||||
|
val kotlinCode =
|
||||||
|
generateKotlinCode(
|
||||||
|
"""
|
||||||
|
module my.mod
|
||||||
|
|
||||||
|
open class Foo { one: Int }
|
||||||
|
abstract class Bar extends Foo { two: String }
|
||||||
|
class Baz extends Bar { three: Duration }
|
||||||
|
class Qux extends Bar {}
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
assertContains(
|
||||||
|
"""
|
||||||
|
| open class Foo(
|
||||||
|
| open val one: Long
|
||||||
|
| ) {
|
||||||
|
| open fun copy(one: Long = this.one): Foo = Foo(one)
|
||||||
|
"""
|
||||||
|
.trimMargin(),
|
||||||
|
kotlinCode
|
||||||
|
)
|
||||||
|
|
||||||
|
assertContains(
|
||||||
|
"""
|
||||||
|
| abstract class Bar(
|
||||||
|
| one: Long,
|
||||||
|
| open val two: String
|
||||||
|
| ) : Foo(one) {
|
||||||
|
"""
|
||||||
|
.trimMargin(),
|
||||||
|
kotlinCode
|
||||||
|
)
|
||||||
|
|
||||||
|
assertContains(
|
||||||
|
"""
|
||||||
|
| class Baz(
|
||||||
|
| one: Long,
|
||||||
|
| two: String,
|
||||||
|
| val three: Duration
|
||||||
|
| ) : Bar(one, two) {
|
||||||
|
| fun copy(
|
||||||
|
| one: Long = this.one,
|
||||||
|
| two: String = this.two,
|
||||||
|
| three: Duration = this.three
|
||||||
|
| ): Baz = Baz(one, two, three)
|
||||||
|
|
|
||||||
|
| override fun copy(one: Long): Baz = Baz(one, two, three)
|
||||||
|
"""
|
||||||
|
.trimMargin(),
|
||||||
|
kotlinCode
|
||||||
|
)
|
||||||
|
|
||||||
|
assertContains(
|
||||||
|
"""
|
||||||
|
| class Qux(
|
||||||
|
| one: Long,
|
||||||
|
| two: String
|
||||||
|
| ) : Bar(one, two) {
|
||||||
|
| fun copy(one: Long = this.one, two: String = this.two): Qux = Qux(one, two)
|
||||||
|
|
|
||||||
|
| override fun copy(one: Long): Qux = Qux(one, two)
|
||||||
|
"""
|
||||||
|
.trimMargin(),
|
||||||
|
kotlinCode
|
||||||
|
)
|
||||||
|
|
||||||
|
assertCompilesSuccessfully(kotlinCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://github.com/apple/pkl/issues/569
|
||||||
|
@Test
|
||||||
|
fun `abstract class that extends open class without adding properties`() {
|
||||||
|
val kotlinCode =
|
||||||
|
generateKotlinCode(
|
||||||
|
"""
|
||||||
|
module my.mod
|
||||||
|
|
||||||
|
open class Foo { one: Int }
|
||||||
|
abstract class Bar extends Foo {}
|
||||||
|
class Baz extends Bar { two: Duration }
|
||||||
|
class Qux extends Bar {}
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
assertContains(
|
||||||
|
"""
|
||||||
|
| open class Foo(
|
||||||
|
| open val one: Long
|
||||||
|
| ) {
|
||||||
|
| open fun copy(one: Long = this.one): Foo = Foo(one)
|
||||||
|
"""
|
||||||
|
.trimMargin(),
|
||||||
|
kotlinCode
|
||||||
|
)
|
||||||
|
|
||||||
|
assertContains(
|
||||||
|
"""
|
||||||
|
| abstract class Bar(
|
||||||
|
| one: Long
|
||||||
|
| ) : Foo(one) {
|
||||||
|
"""
|
||||||
|
.trimMargin(),
|
||||||
|
kotlinCode
|
||||||
|
)
|
||||||
|
|
||||||
|
assertContains(
|
||||||
|
"""
|
||||||
|
| class Baz(
|
||||||
|
| one: Long,
|
||||||
|
| val two: Duration
|
||||||
|
| ) : Bar(one) {
|
||||||
|
| fun copy(one: Long = this.one, two: Duration = this.two): Baz = Baz(one, two)
|
||||||
|
|
|
||||||
|
| override fun copy(one: Long): Baz = Baz(one, two)
|
||||||
|
"""
|
||||||
|
.trimMargin(),
|
||||||
|
kotlinCode
|
||||||
|
)
|
||||||
|
|
||||||
|
assertContains(
|
||||||
|
"""
|
||||||
|
| class Qux(
|
||||||
|
| one: Long
|
||||||
|
| ) : Bar(one) {
|
||||||
|
| override fun copy(one: Long): Qux = Qux(one)
|
||||||
|
"""
|
||||||
|
.trimMargin(),
|
||||||
|
kotlinCode
|
||||||
|
)
|
||||||
|
|
||||||
|
assertCompilesSuccessfully(kotlinCode)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun keywords() {
|
fun keywords() {
|
||||||
val props = kotlinKeywords.joinToString("\n") { "`$it`: Int" }
|
val props = kotlinKeywords.joinToString("\n") { "`$it`: Int" }
|
||||||
|
|||||||
Reference in New Issue
Block a user