aboutsummaryrefslogtreecommitdiff
path: root/plugins/base/src
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/base/src')
-rw-r--r--plugins/base/src/main/kotlin/signatures/KotlinSignatureProvider.kt38
-rw-r--r--plugins/base/src/main/kotlin/translators/documentables/DefaultPageCreator.kt2
-rw-r--r--plugins/base/src/test/kotlin/content/functions/ContentForBriefTest.kt77
-rw-r--r--plugins/base/src/test/kotlin/content/signatures/ConstructorsSignaturesTest.kt146
-rw-r--r--plugins/base/src/test/kotlin/signatures/SignatureTest.kt65
5 files changed, 247 insertions, 81 deletions
diff --git a/plugins/base/src/main/kotlin/signatures/KotlinSignatureProvider.kt b/plugins/base/src/main/kotlin/signatures/KotlinSignatureProvider.kt
index 1da8e3d1..22f67445 100644
--- a/plugins/base/src/main/kotlin/signatures/KotlinSignatureProvider.kt
+++ b/plugins/base/src/main/kotlin/signatures/KotlinSignatureProvider.kt
@@ -309,24 +309,28 @@ class KotlinSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLog
annotationsBlock(f)
f.visibility[sourceSet]?.takeIf { it !in ignoredVisibilities }?.name?.let { keyword("$it ") }
if (f.isExpectActual) keyword(if (sourceSet == f.expectPresentInSet) "expect " else "actual ")
- f.modifier[sourceSet]?.takeIf { it !in ignoredModifiers }?.let {
- if (it is JavaModifier.Empty) KotlinModifier.Open else it
- }?.name?.let { keyword("$it ") }
- f.modifiers()[sourceSet]?.toSignatureString()?.let { keyword(it) }
- keyword("fun ")
- val usedGenerics = if (f.isConstructor) f.generics.filter { f uses it } else f.generics
- list(usedGenerics, prefix = "<", suffix = "> ",
- separatorStyles = mainStyles + TokenStyle.Punctuation,
- surroundingCharactersStyle = mainStyles + TokenStyle.Operator) {
- annotationsInline(it)
- +buildSignature(it)
- }
- f.receiver?.also {
- signatureForProjection(it.type)
- punctuation(".")
+ if (f.isConstructor) {
+ keyword("constructor")
+ } else {
+ f.modifier[sourceSet]?.takeIf { it !in ignoredModifiers }?.let {
+ if (it is JavaModifier.Empty) KotlinModifier.Open else it
+ }?.name?.let { keyword("$it ") }
+ f.modifiers()[sourceSet]?.toSignatureString()?.let { keyword(it) }
+ keyword("fun ")
+ list(
+ f.generics, prefix = "<", suffix = "> ",
+ separatorStyles = mainStyles + TokenStyle.Punctuation,
+ surroundingCharactersStyle = mainStyles + TokenStyle.Operator
+ ) {
+ annotationsInline(it)
+ +buildSignature(it)
+ }
+ f.receiver?.also {
+ signatureForProjection(it.type)
+ punctuation(".")
+ }
+ link(f.name, f.dri, styles = mainStyles + TokenStyle.Function + f.stylesIfDeprecated(sourceSet))
}
- link(f.name, f.dri, styles = mainStyles + TokenStyle.Function + f.stylesIfDeprecated(sourceSet))
-
// for a function, opening and closing parentheses must be present
// anyway, even if it has no parameters, resulting in `fun test(): R`
punctuation("(")
diff --git a/plugins/base/src/main/kotlin/translators/documentables/DefaultPageCreator.kt b/plugins/base/src/main/kotlin/translators/documentables/DefaultPageCreator.kt
index 12fbb33c..ff60170c 100644
--- a/plugins/base/src/main/kotlin/translators/documentables/DefaultPageCreator.kt
+++ b/plugins/base/src/main/kotlin/translators/documentables/DefaultPageCreator.kt
@@ -377,7 +377,7 @@ open class DefaultPageCreator(
"Constructors",
2,
ContentKind.Constructors,
- constructorsToDocumented.groupBy { it.parameters.map { it.dri } }
+ constructorsToDocumented.groupBy { it.name }
.map { (_, v) -> v.first().name to v },
@Suppress("UNCHECKED_CAST")
(csWithConstructor as List<Documentable>).sourceSets,
diff --git a/plugins/base/src/test/kotlin/content/functions/ContentForBriefTest.kt b/plugins/base/src/test/kotlin/content/functions/ContentForBriefTest.kt
index 50f9e357..f86506af 100644
--- a/plugins/base/src/test/kotlin/content/functions/ContentForBriefTest.kt
+++ b/plugins/base/src/test/kotlin/content/functions/ContentForBriefTest.kt
@@ -1,12 +1,14 @@
package content.functions
import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest
+import org.jetbrains.dokka.links.DRI
import org.jetbrains.dokka.links.TypeConstructor
import org.jetbrains.dokka.model.DClass
import org.jetbrains.dokka.model.dfs
import org.jetbrains.dokka.pages.*
-import org.junit.Assert.assertEquals
+import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
+import kotlin.test.assertNotNull
import kotlin.test.assertNull
@@ -55,26 +57,19 @@ class ContentForBriefTest : BaseAbstractTest() {
|}
""".trimIndent()
+
@Test
fun `primary constructor should not inherit docs from its parameter`() {
testInline(codeWithSecondaryAndPrimaryConstructorsDocumented, testConfiguration) {
pagesTransformationStage = { module ->
- val classPage =
- module.dfs { it.name == "Example" && (it as WithDocumentables).documentables.firstOrNull() is DClass } as ContentPage
- val constructorsTable =
- classPage.content.dfs { it is ContentTable && it.dci.kind == ContentKind.Constructors } as ContentTable
+ val classPage = module.findClassPage("Example")
- assertEquals(2, constructorsTable.children.size)
- val primary = constructorsTable.children.first {
- it.dci.dri.first().callable?.params?.first() == TypeConstructor(
- "kotlin.Int",
- emptyList()
- )
+ val constructorsWithBriefs = classPage.findConstructorsWithBriefs()
+ val constructorDocs = constructorsWithBriefs.findConstructorDocs {
+ it.callable?.params?.first() == TypeConstructor("kotlin.Int", emptyList())
}
- val primaryConstructorDocs =
- primary.dfs { it is ContentText && it.dci.kind == ContentKind.Comment } as ContentText
- assertEquals("constructor docs", primaryConstructorDocs.text)
+ assertEquals("constructor docs", constructorDocs.text)
}
}
}
@@ -83,32 +78,47 @@ class ContentForBriefTest : BaseAbstractTest() {
fun `secondary constructor should not inherit docs from its parameter`() {
testInline(codeWithSecondaryAndPrimaryConstructorsDocumented, testConfiguration) {
pagesTransformationStage = { module ->
- val classPage =
- module.dfs { it.name == "Example" && (it as WithDocumentables).documentables.firstOrNull() is DClass } as ContentPage
- val constructorsTable =
- classPage.content.dfs { it is ContentTable && it.dci.kind == ContentKind.Constructors } as ContentTable
+ val classPage = module.findClassPage("Example")
- assertEquals(2, constructorsTable.children.size)
- val primary = constructorsTable.children.first {
- it.dci.dri.first().callable?.params?.first() == TypeConstructor(
- "kotlin.String",
- emptyList()
- )
+ val constructorsWithBriefs = classPage.findConstructorsWithBriefs()
+ val constructorDocs = constructorsWithBriefs.findConstructorDocs {
+ it.callable?.params?.first() == TypeConstructor("kotlin.String", emptyList())
}
- val primaryConstructorDocs =
- primary.dfs { it is ContentText && it.dci.kind == ContentKind.Comment } as ContentText
- assertEquals("secondary constructor", primaryConstructorDocs.text)
+ assertEquals("secondary constructor", constructorDocs.text)
}
}
}
+ /**
+ * All constructors are merged in one block (like overloaded functions).
+ * That leads to the structure where content block (`constructorsWithBriefs`) consist of plain list
+ * of constructors and briefs. In that list constructor is above, brief is below.
+ */
+ private fun ContentPage.findConstructorsWithBriefs(): List<ContentNode> {
+ val constructorsTable = this.content.dfs {
+ it is ContentTable && it.dci.kind == ContentKind.Constructors
+ } as ContentTable
+
+ val constructorsWithBriefs = constructorsTable.dfs {
+ it is ContentGroup && it.dci.kind == ContentKind.SourceSetDependentHint
+ }?.children
+ assertNotNull(constructorsWithBriefs, "Content node with constructors and briefs is not found")
+
+ return constructorsWithBriefs
+ }
+
+ private fun List<ContentNode>.findConstructorDocs(constructorMatcher: (DRI) -> Boolean): ContentText {
+ val constructorIndex = this.indexOfFirst { constructorMatcher(it.dci.dri.first()) }
+ return this[constructorIndex + 1] // expect that the relevant comment is below the constructor
+ .dfs { it is ContentText && it.dci.kind == ContentKind.Comment } as ContentText
+ }
+
@Test
fun `primary constructor should not inherit docs from its parameter when no specific docs are provided`() {
testInline(codeWithDocumentedParameter, testConfiguration) {
pagesTransformationStage = { module ->
- val classPage =
- module.dfs { it.name == "Example" && (it as WithDocumentables).documentables.firstOrNull() is DClass } as ContentPage
+ val classPage = module.findClassPage("Example")
val constructorsTable =
classPage.content.dfs { it is ContentTable && it.dci.kind == ContentKind.Constructors } as ContentTable
@@ -318,8 +328,15 @@ class ContentForBriefTest : BaseAbstractTest() {
}
}
+ private fun RootPageNode.findClassPage(className: String): ContentPage {
+ return this.dfs {
+ it.name == className && (it as WithDocumentables).documentables.firstOrNull() is DClass
+ } as ContentPage
+ }
+
private fun RootPageNode.singleFunctionDescription(className: String): ContentGroup {
- val classPage = dfs { it.name == className && (it as WithDocumentables).documentables.firstOrNull() is DClass } as ContentPage
+ val classPage =
+ dfs { it.name == className && (it as WithDocumentables).documentables.firstOrNull() is DClass } as ContentPage
val functionsTable =
classPage.content.dfs { it is ContentTable && it.dci.kind == ContentKind.Functions } as ContentTable
diff --git a/plugins/base/src/test/kotlin/content/signatures/ConstructorsSignaturesTest.kt b/plugins/base/src/test/kotlin/content/signatures/ConstructorsSignaturesTest.kt
index 943d1bc4..c8c088f7 100644
--- a/plugins/base/src/test/kotlin/content/signatures/ConstructorsSignaturesTest.kt
+++ b/plugins/base/src/test/kotlin/content/signatures/ConstructorsSignaturesTest.kt
@@ -1,11 +1,9 @@
package content.signatures
import matchers.content.*
-import org.jetbrains.dokka.pages.ContentPage
import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest
+import org.jetbrains.dokka.pages.ContentPage
import org.junit.jupiter.api.Test
-import utils.ParamAttributes
-import utils.functionSignature
class ConstructorsSignaturesTest : BaseAbstractTest() {
private val testConfiguration = dokkaConfiguration {
@@ -196,24 +194,133 @@ class ConstructorsSignaturesTest : BaseAbstractTest() {
table {
group {
link { +"SomeClass" }
- functionSignature(
- annotations = emptyMap(),
- visibility = "",
- modifier = "",
- keywords = emptySet(),
- name = "SomeClass"
- )
+ platformHinted {
+ group {
+ +"constructor"
+ +"("
+ +")"
+ }
+ group {
+ +"constructor"
+ +"("
+ group {
+ group {
+ +"a: "
+ group { link { +"String" } }
+ }
+ }
+ +")"
+ }
+ }
+ }
+ }
+ skipAllNotMatching()
+ }
+ }
+ }
+ }
+ }
+
+
+ @Test
+ fun `class with a few documented constructors`() {
+ testInline(
+ """
+ |/src/main/kotlin/test/source.kt
+ |package test
+ |
+ | /**
+ | * some comment
+ | * @constructor ctor comment
+ | **/
+ |class SomeClass(a: String){
+ | /**
+ | * ctor one
+ | **/
+ | constructor(): this("")
+ |
+ | /**
+ | * ctor two
+ | **/
+ | constructor(b: Int): this("")
+ |}
+ """.trimIndent(), testConfiguration
+ ) {
+ pagesTransformationStage = { module ->
+ val page = module.children.single { it.name == "test" }
+ .children.single { it.name == "SomeClass" } as ContentPage
+ page.content.assertNode {
+ group {
+ header(1) { +"SomeClass" }
+ platformHinted {
+ group {
+ +"class "
+ link { +"SomeClass" }
+ +"("
+ group {
+ group {
+ +"a: "
+ group { link { +"String" } }
+ }
+ }
+ +")"
}
+ skipAllNotMatching()
+ }
+ }
+ group {
+ header { +"Constructors" }
+ table {
group {
link { +"SomeClass" }
- functionSignature(
- annotations = emptyMap(),
- visibility = "",
- modifier = "",
- keywords = emptySet(),
- name = "SomeClass",
- params = listOf("a" to ParamAttributes(emptyMap(), emptySet(), "String")).toTypedArray()
- )
+ platformHinted {
+ group {
+ +"constructor"
+ +"("
+ +")"
+ }
+ group {
+ group {
+ group { +"ctor one" }
+ }
+ }
+ group {
+ +"constructor"
+ +"("
+ group {
+ group {
+ +"b: "
+ group {
+ link { +"Int" }
+ }
+ }
+ }
+ +")"
+ }
+ group {
+ group {
+ group { +"ctor two" }
+ }
+ }
+ group {
+ +"constructor"
+ +"("
+ group {
+ group {
+ +"a: "
+ group {
+ link { +"String" }
+ }
+ }
+ }
+ +")"
+ }
+ group {
+ group {
+ group { +"ctor comment" }
+ }
+ }
+ }
}
}
skipAllNotMatching()
@@ -266,8 +373,7 @@ class ConstructorsSignaturesTest : BaseAbstractTest() {
link { +"SomeClass" }
platformHinted {
group {
- +"fun "
- link { +"SomeClass" }
+ +"constructor"
+"("
group {
group {
diff --git a/plugins/base/src/test/kotlin/signatures/SignatureTest.kt b/plugins/base/src/test/kotlin/signatures/SignatureTest.kt
index 13e103b4..77c92d9c 100644
--- a/plugins/base/src/test/kotlin/signatures/SignatureTest.kt
+++ b/plugins/base/src/test/kotlin/signatures/SignatureTest.kt
@@ -8,7 +8,6 @@ import org.jetbrains.dokka.model.dfs
import org.junit.jupiter.api.Test
import utils.*
import kotlin.test.assertEquals
-import kotlin.test.assertFalse
class SignatureTest : BaseAbstractTest() {
private val configuration = dokkaConfiguration {
@@ -760,38 +759,50 @@ class SignatureTest : BaseAbstractTest() {
writerPlugin.writer.renderedContent("root/example/-generic-class/-generic-class.html").signature().zip(
listOf(
arrayOf(
- "fun <", A("T"), "> ", A("GenericClass"), "(", Parameters(
+ "constructor(",
+ Parameters(
Parameter("x: ", A("T"))
- ), ")",
+ ),
+ ")",
),
arrayOf(
- "fun ", A("GenericClass"), "(", Parameters(
+ "constructor(",
+ Parameters(
Parameter("x: ", A("Int"), ", "),
Parameter("y: ", A("String"))
- ), ")",
+ ),
+ ")",
),
arrayOf(
- "fun <", A("T"), "> ", A("GenericClass"), "(", Parameters(
+ "constructor(",
+ Parameters(
Parameter("x: ", A("Int"), ", "),
Parameter("y: ", A("List"), "<", A("T"), ">")
- ), ")",
+ ),
+ ")",
),
arrayOf(
- "fun ", A("GenericClass"), "(", Parameters(
+ "constructor(",
+ Parameters(
Parameter("x: ", A("Boolean"), ", "),
Parameter("y: ", A("Int"), ", "),
Parameter("z:", A("String"))
- ), ")",
+ ),
+ ")",
),
arrayOf(
- "fun <", A("T"), "> ", A("GenericClass"), "(", Parameters(
+ "constructor(",
+ Parameters(
Parameter("x: ", A("List"), "<", A("Comparable"), "<", A("Lazy"), "<", A("T"), ">>>?")
- ), ")",
+ ),
+ ")",
),
arrayOf(
- "fun ", A("GenericClass"), "(", Parameters(
+ "constructor(",
+ Parameters(
Parameter("x: ", A("Int"))
- ), ")",
+ ),
+ ")",
),
)
).forEach {
@@ -802,6 +813,34 @@ class SignatureTest : BaseAbstractTest() {
}
@Test
+ fun `constructor has its own custom signature keyword in Constructor tab`() {
+ val writerPlugin = TestOutputWriterPlugin()
+
+ testInline(
+ """
+ |/src/main/kotlin/common/Test.kt
+ |package example
+ |
+ |class PrimaryConstructorClass(x: String) { }
+ """.trimMargin(),
+ configuration,
+ pluginOverrides = listOf(writerPlugin)
+ ) {
+ renderingStage = { _, _ ->
+ val constructorTabFirstElement =
+ writerPlugin.writer.renderedContent("root/example/-primary-constructor-class/index.html")
+ .tab("Constructors")
+ .first() ?: throw NoSuchElementException("No Constructors tab found or it is empty")
+
+ constructorTabFirstElement.firstSignature().match(
+ "constructor(", Parameters(Parameter("x: ", A("String"))), ")",
+ ignoreSpanWithTokenStyle = true
+ )
+ }
+ }
+ }
+
+ @Test
fun `primary constructor with properties check for all tokens`() {
val writerPlugin = TestOutputWriterPlugin()