From ba56d17cece0b500446751bc0839a1ecc7a59d23 Mon Sep 17 00:00:00 2001 From: Ilya Matveev Date: Tue, 20 Feb 2018 14:38:29 +0300 Subject: [PATCH] [klib] Don't print 'final' modality --- .../jetbrains/kotlin/cli/klib/KlibPrinter.kt | 67 +++++--- .../org/jetbrains/kotlin/cli/klib/main.kt | 5 +- .../kotlin/cli/klib/test/ContentsTest.kt | 145 ++++++++++++------ klib/src/test/testData/FunctionModifiers.kt | 8 + klib/src/test/testData/MethodModality.kt | 20 +++ 5 files changed, 176 insertions(+), 69 deletions(-) create mode 100644 klib/src/test/testData/FunctionModifiers.kt create mode 100644 klib/src/test/testData/MethodModality.kt diff --git a/klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/KlibPrinter.kt b/klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/KlibPrinter.kt index ea2f4e65fa6..c7b1ac92e4e 100644 --- a/klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/KlibPrinter.kt +++ b/klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/KlibPrinter.kt @@ -29,21 +29,6 @@ import org.jetbrains.kotlin.utils.Printer class KlibPrinter(out: Appendable) { val printer = Printer(out, 1, " ") - val renderer = DescriptorRenderer.COMPACT_WITH_SHORT_TYPES.withOptions { - modifiers = DescriptorRendererModifier.ALL - overrideRenderingPolicy = OverrideRenderingPolicy.RENDER_OVERRIDE - annotationArgumentsRenderingPolicy = AnnotationArgumentsRenderingPolicy.UNLESS_EMPTY - excludedAnnotationClasses += setOf(KotlinBuiltIns.FQ_NAMES.suppress) - - classWithPrimaryConstructor = true - renderConstructorKeyword = true - includePropertyConstant = true - - unitReturnType = false - withDefinedIn = false - renderDefaultVisibility = false - secondaryConstructorsAsPrimary = false - } val DeclarationDescriptorWithVisibility.isPublicOrProtected: Boolean get() = visibility == Visibilities.PUBLIC || visibility == Visibilities.PROTECTED @@ -64,6 +49,27 @@ class KlibPrinter(out: Appendable) { println() } + private fun ClassDescriptor.render(): String { + val renderer = when (modality) { + // Don't render 'final' modality + Modality.FINAL -> Renderers.WITHOUT_MODALITY + else -> Renderers.DEFAULT + } + return renderer.render(this) + } + + private fun CallableMemberDescriptor.render(): String { + val containingDeclaration = containingDeclaration + val renderer = when { + // Don't render modality for non-override final methods and interface methods. + containingDeclaration is ClassDescriptor && containingDeclaration.kind == ClassKind.INTERFACE || + modality == Modality.FINAL && overriddenDescriptors.isEmpty() -> + Renderers.WITHOUT_MODALITY + else -> Renderers.DEFAULT + } + return renderer.render(this) + } + fun print(module: ModuleDescriptor) { module.accept(PrinterVisitor(), Unit) } @@ -89,7 +95,7 @@ class KlibPrinter(out: Appendable) { override fun visitClassDescriptor(descriptor: ClassDescriptor, data: Unit) { val children = descriptor.unsubstitutedMemberScope.getContributedDescriptors().filter { it.shouldBePrinted } val constructors = descriptor.constructors.filter { !it.isPrimary && it.shouldBePrinted } - val header = renderer.render(descriptor) + val header = descriptor.render() if (children.isNotEmpty() || constructors.isNotEmpty()) { printer.printBody(header) { constructors.forEach { it.accept(this, data) } @@ -102,15 +108,36 @@ class KlibPrinter(out: Appendable) { } override fun visitFunctionDescriptor(descriptor: FunctionDescriptor, data: Unit) { - printer.println(renderer.render(descriptor)) + printer.println(descriptor.render()) } override fun visitPropertyDescriptor(descriptor: PropertyDescriptor, data: Unit) { - printer.println(renderer.render(descriptor)) + printer.println(descriptor.render()) } - override fun visitConstructorDescriptor(constructorDescriptor: ConstructorDescriptor, data: Unit) { - printer.println(renderer.render(constructorDescriptor)) + override fun visitConstructorDescriptor(descriptor: ConstructorDescriptor, data: Unit) { + printer.println(descriptor.render()) + } + } + + object Renderers { + val DEFAULT = DescriptorRenderer.COMPACT_WITH_SHORT_TYPES.withOptions { + modifiers = DescriptorRendererModifier.ALL + overrideRenderingPolicy = OverrideRenderingPolicy.RENDER_OVERRIDE + annotationArgumentsRenderingPolicy = AnnotationArgumentsRenderingPolicy.UNLESS_EMPTY + excludedAnnotationClasses += setOf(KotlinBuiltIns.FQ_NAMES.suppress) + + classWithPrimaryConstructor = true + renderConstructorKeyword = true + includePropertyConstant = true + + unitReturnType = false + withDefinedIn = false + renderDefaultVisibility = false + secondaryConstructorsAsPrimary = false + } + val WITHOUT_MODALITY = DEFAULT.withOptions { + modifiers -= DescriptorRendererModifier.MODALITY } } diff --git a/klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/main.kt b/klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/main.kt index e93c418ef0c..cc57be75487 100644 --- a/klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/main.kt +++ b/klib/src/main/kotlin/org/jetbrains/kotlin/cli/klib/main.kt @@ -143,8 +143,7 @@ class Library(val name: String, val requestedRepository: String?, val target: St fun contents(output: Appendable = out) { val reader = LibraryReaderImpl(libraryInRepoOrCurrentDir(repository, name), currentAbiVersion) - // TODO: Should the klib tool have arguments like compilerVersion or apiVersion? - val versionSpec = LanguageVersionSettingsImpl(LanguageVersion.LATEST_STABLE, ApiVersion.LATEST_STABLE) + val versionSpec = LanguageVersionSettingsImpl(currentLanguageVersion, currentApiVersion) val module = reader.moduleDescriptor(versionSpec) val defaultModules = mutableListOf() if (!module.isStdlib()) { @@ -169,6 +168,8 @@ class Library(val name: String, val requestedRepository: String?, val target: St // TODO: need to do something here. val currentAbiVersion = 1 +val currentLanguageVersion = LanguageVersion.LATEST_STABLE +val currentApiVersion = ApiVersion.LATEST_STABLE fun libraryInRepo(repository: File, name: String): File { val resolver = KonanLibrarySearchPathResolver( diff --git a/klib/src/test/kotlin/org/jetbrains/kotlin/cli/klib/test/ContentsTest.kt b/klib/src/test/kotlin/org/jetbrains/kotlin/cli/klib/test/ContentsTest.kt index 465ec01069d..df56b46857c 100644 --- a/klib/src/test/kotlin/org/jetbrains/kotlin/cli/klib/test/ContentsTest.kt +++ b/klib/src/test/kotlin/org/jetbrains/kotlin/cli/klib/test/ContentsTest.kt @@ -26,10 +26,13 @@ class ContentsTest { private fun testLibrary(name: String) = LIBRARY_DIRECTORY.resolve("$name.klib").toFile().absolutePath - private fun klibContents(library: String, expected: () -> String) { + private fun klibContents(library: String, printOutput: Boolean = false, expected: () -> String) { val output = StringBuilder() val lib = Library(library, null, "host") lib.contents(output) + if (printOutput) { + println(output.trim().toString()) + } assertEquals(expected(), output.trim().toString(), "klib contents test failed for library: $library") } @@ -59,9 +62,9 @@ class ContentsTest { inline fun t4(x: T) fun t5(x: T) fun Foo.e() - final annotation class A constructor() : Annotation - final annotation class B constructor() : Annotation - final class Foo constructor() + annotation class A constructor() : Annotation + annotation class B constructor() : Annotation + class Foo constructor() } """.trimIndent() } @@ -70,11 +73,11 @@ class ContentsTest { fun constructors() = klibContents(testLibrary("Constructors")) { """ package { - final annotation class A constructor() : Annotation - final class Bar @A constructor(x: Int) - final class Baz private constructor(x: Int) + annotation class A constructor() : Annotation + class Bar @A constructor(x: Int) + class Baz private constructor(x: Int) - final class Foo constructor(x: Int) { + class Foo constructor(x: Int) { constructor() constructor(x: Double) constructor(x: Double, y: Int) @@ -82,9 +85,9 @@ class ContentsTest { @A constructor(x: Foo) } - final class Qux protected constructor(x: Int) + class Qux protected constructor(x: Int) - final class Typed constructor(x: Int) { + class Typed constructor(x: Int) { constructor() constructor(x: Double) constructor(x: Double, y: Int) @@ -102,25 +105,25 @@ class ContentsTest { package { object A { - final fun a() + fun a() } - final class B constructor() { + class B constructor() { object C { - final fun c() + fun c() } companion object { - final fun b() + fun b() } } - final class D constructor() { + class D constructor() { companion object E { - final fun e() + fun e() } } @@ -134,54 +137,54 @@ class ContentsTest { """ package { - final class A constructor() { - final val aVal: Int = 0 - final var aVar: String - final fun aFun() + class A constructor() { + val aVal: Int = 0 + var aVar: String + fun aFun() - final inner class B constructor() { - final val bVal: Int = 0 - final var bVar: String - final fun bFun() + inner class B constructor() { + val bVal: Int = 0 + var bVar: String + fun bFun() - final inner class C constructor() { - final val cVal: Int = 0 - final var cVar: String - final fun cFun() + inner class C constructor() { + val cVal: Int = 0 + var cVar: String + fun cFun() } } - final class E constructor() { - final val eVal: Int = 0 - final var eVar: String - final fun eFun() + class E constructor() { + val eVal: Int = 0 + var eVar: String + fun eFun() } } - final data class F constructor(fVal: Int, fVar: String) { - final val fVal: Int - final var fVar: String - final operator fun component1(): Int - final operator fun component2(): String - final fun copy(fVal: Int = ..., fVar: String = ...): F + data class F constructor(fVal: Int, fVar: String) { + val fVal: Int + var fVar: String + operator fun component1(): Int + operator fun component2(): String + fun copy(fVal: Int = ..., fVar: String = ...): F override fun equals(other: Any?): Boolean - final fun fFun() + fun fFun() override fun hashCode(): Int override fun toString(): String } - final class FinalImpl constructor() : OpenImpl { + class FinalImpl constructor() : OpenImpl { override val iVal: Int = 0 override var iVar: String override fun iFun() } interface Interface { - abstract val iVal: Int - abstract var iVar: String - abstract fun iFun() + val iVal: Int + var iVar: String + fun iFun() } open class OpenImpl constructor() : Interface { @@ -194,13 +197,61 @@ class ContentsTest { """.trimIndent() } + @Test + fun methodModality() = klibContents(testLibrary("MethodModality")) { + """ + package { + + abstract class AbstractClass constructor() : Interface { + abstract fun abstractFun() + override fun interfaceFun() + } + + class FinalClass constructor() : OpenClass { + override fun openFun1() + final override fun openFun2() + } + + interface Interface { + fun interfaceFun() + } + + open class OpenClass constructor() : AbstractClass { + override fun abstractFun() + fun finalFun() + open fun openFun1() + open fun openFun2() + } + + } + """.trimIndent() + } + + @Test + fun functionModifiers() = klibContents(testLibrary("FunctionModifiers")) { + """ + package { + + class Foo constructor() { + fun f1() + infix fun f2(x: Int) + suspend fun f3() + tailrec fun f4() + fun f5(vararg x: Int) + operator fun plus(x: Int) + } + + } + """.trimIndent() + } + @Test @Ignore // TODO: Do we need to print the overridden method in the C entry? fun enum() = klibContents(testLibrary("Enum")) { """ package { - final enum class E private constructor(x: Int = ...) : Enum { + enum class E private constructor(x: Int = ...) : Enum { enum entry A enum entry B @@ -208,9 +259,9 @@ class ContentsTest { override fun enumFun(): Int } - final val enumVal: Int = 0 - final var enumVar: String - final val x: Int + val enumVal: Int = 0 + var enumVar: String + val x: Int open fun enumFun(): Int } diff --git a/klib/src/test/testData/FunctionModifiers.kt b/klib/src/test/testData/FunctionModifiers.kt new file mode 100644 index 00000000000..80b83ab2f3b --- /dev/null +++ b/klib/src/test/testData/FunctionModifiers.kt @@ -0,0 +1,8 @@ +class Foo { + fun f1() {} + infix fun f2(x: Int) {} + suspend fun f3() {} + operator fun plus(x: Int) {} + tailrec fun f4() {} + fun f5(vararg x: Int) {} +} \ No newline at end of file diff --git a/klib/src/test/testData/MethodModality.kt b/klib/src/test/testData/MethodModality.kt new file mode 100644 index 00000000000..01844360ede --- /dev/null +++ b/klib/src/test/testData/MethodModality.kt @@ -0,0 +1,20 @@ +interface Interface { + fun interfaceFun() +} + +abstract class AbstractClass: Interface { + override fun interfaceFun() {} + abstract fun abstractFun() +} + +open class OpenClass: AbstractClass() { + override fun abstractFun() {} + open fun openFun1() {} + open fun openFun2() {} + fun finalFun() {} +} + +class FinalClass: OpenClass() { + override fun openFun1() {} + final override fun openFun2() {} +} \ No newline at end of file