diff options
author | CharlesG-Branch <43424788+CharlesG-Branch@users.noreply.github.com> | 2022-02-18 07:39:33 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-02-18 15:39:33 +0300 |
commit | df4780c31026aaa626746f49f0e6fa3fa0278a05 (patch) | |
tree | 5d562bcbf2240d8a1bd50ef5f97040088b68f781 /plugins/base/src | |
parent | 9a1434d583b931671e2c5e9c5275af725938d503 (diff) | |
download | dokka-df4780c31026aaa626746f49f0e6fa3fa0278a05.tar.gz dokka-df4780c31026aaa626746f49f0e6fa3fa0278a05.tar.bz2 dokka-df4780c31026aaa626746f49f0e6fa3fa0278a05.zip |
Fix java getter / setter name generation (#2356)
Kotlin has special rules for conversion around properties that start with "is"
For more info see:
https://kotlinlang.org/docs/java-interop.html#getters-and-setters
https://kotlinlang.org/docs/java-to-kotlin-interop.html#properties
Diffstat (limited to 'plugins/base/src')
-rw-r--r-- | plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt | 20 | ||||
-rw-r--r-- | plugins/base/src/test/kotlin/translators/AccessorMethodNamingTest.kt | 118 |
2 files changed, 136 insertions, 2 deletions
diff --git a/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt b/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt index 96bd2fc0..f636f984 100644 --- a/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt +++ b/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt @@ -616,9 +616,25 @@ private class DokkaDescriptorVisitor( ) val name = run { - val modifier = if (isGetter) "get" else "set" val rawName = propertyDescriptor.name.asString() - "$modifier${rawName.capitalize()}" + /* + * Kotlin has special rules for conversion around properties that + * start with "is" For more info see: + * https://kotlinlang.org/docs/java-interop.html#getters-and-setters + * https://kotlinlang.org/docs/java-to-kotlin-interop.html#properties + * + * Based on our testing, this rule only applies when the letter after + * the "is" is *not* lowercase. This means that words like "issue" won't + * have the rule applied but "is_foobar" and "is1of" will have the rule applied. + */ + val specialCaseIs = rawName.startsWith("is") + && rawName.getOrNull(2)?.isLowerCase() == false + + if (specialCaseIs) { + if (isGetter) rawName else rawName.replaceFirst("is", "set") + } else { + if (isGetter) "get${rawName.capitalize()}" else "set${rawName.capitalize()}" + } } val parameters = diff --git a/plugins/base/src/test/kotlin/translators/AccessorMethodNamingTest.kt b/plugins/base/src/test/kotlin/translators/AccessorMethodNamingTest.kt new file mode 100644 index 00000000..aeea194f --- /dev/null +++ b/plugins/base/src/test/kotlin/translators/AccessorMethodNamingTest.kt @@ -0,0 +1,118 @@ +package translators + +import org.junit.jupiter.api.Assertions.* +import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest +import org.jetbrains.dokka.model.DProperty +import org.junit.jupiter.api.Test + +/** + * https://kotlinlang.org/docs/java-to-kotlin-interop.html#properties + * https://kotlinlang.org/docs/java-interop.html#getters-and-setters + */ +class AccessorMethodNamingTest : BaseAbstractTest() { + + @Test + fun `standard property`() { + testAccessors("data class TestCase(var standardString: String, var standardBoolean: Boolean)") { + doTest("standardString", "getStandardString", "setStandardString") + doTest("standardBoolean", "getStandardBoolean", "setStandardBoolean") + } + } + + @Test + fun `properties that start with the word 'is' use the special is rules`() { + testAccessors("data class TestCase(var isFoo: String, var isBar: Boolean)") { + doTest("isFoo", "isFoo", "setFoo") + doTest("isBar", "isBar", "setBar") + } + } + + @Test + fun `properties that start with a word that starts with 'is' use get and set`() { + testAccessors("data class TestCase(var issuesFetched: Int, var issuesWereDisplayed: Boolean)") { + doTest("issuesFetched", "getIssuesFetched", "setIssuesFetched") + doTest("issuesWereDisplayed", "getIssuesWereDisplayed", "setIssuesWereDisplayed") + } + } + + @Test + fun `properties that start with the word 'is' followed by underscore use the special is rules`() { + testAccessors("data class TestCase(var is_foo: String, var is_bar: Boolean)") { + doTest("is_foo", "is_foo", "set_foo") + doTest("is_bar", "is_bar", "set_bar") + } + } + + @Test + fun `properties that start with the word 'is' followed by a number use the special is rules`() { + testAccessors("data class TestCase(var is1of: String, var is2of: Boolean)") { + doTest("is1of", "is1of", "set1of") + doTest("is2of", "is2of", "set2of") + } + } + + @Test + fun `sanity check short names`() { + testAccessors( + """ + data class TestCase( + var i: Boolean, + var `is`: Boolean, + var isz: Boolean, + var isA: Int, + var isB: Boolean, + ) + """.trimIndent() + ) { + doTest("i", "getI", "setI") + doTest("is", "getIs", "setIs") + doTest("isz", "getIsz", "setIsz") + doTest("isA", "isA", "setA") + doTest("isB", "isB", "setB") + } + } + + private fun testAccessors(code: String, block: PropertyTestCase.() -> Unit) { + val configuration = dokkaConfiguration { + suppressObviousFunctions = false + sourceSets { + sourceSet { + sourceRoots = listOf("src/main/kotlin") + } + } + } + + testInline(""" + /src/main/kotlin/sample/TestCase.kt + package sample + + $code + """.trimIndent(), + configuration) { + documentablesMergingStage = { module -> + val properties = module.packages.single().classlikes.first().properties + PropertyTestCase(properties).apply { + block() + finish() + } + } + } + } + + private class PropertyTestCase(private val properties: List<DProperty>) { + private var testsDone: Int = 0 + + fun doTest(kotlinName: String, getter: String? = null, setter: String? = null) { + properties.first { it.name == kotlinName }.let { + assertEquals(getter, it.getter?.name) + assertEquals(setter, it.setter?.name) + } + testsDone += 1 + } + + fun finish() { + assertTrue(testsDone > 0, "No tests in TestCase") + assertEquals(testsDone, properties.size) + } + } +}
\ No newline at end of file |