Skip to content

Commit

Permalink
Refactor and document DisplaySourceSet, deprecate SelfRepresentingSin…
Browse files Browse the repository at this point in the history
…gletonSet (#3105)


* Deprecate internal API SelfRepresentingSingletonSet for removal as being harmful and unimplement it in DisplaySourceSet
* Provide no automatic migration for DisplaySourceSet, as there are no mechanisms for that. Manual migration is the replacement of 'dss' to `setOf(dss)` where applicable
* Introduce a convenience-member DefaultRenderer.buildContentNode to avoid wrapping DSS into set manually
* Document DisplaySourceSet
* Replace Iterable<DisplaySourceSet>.sourceSetIDs with more straightforward Iterable<DisplaySourceSet>.computeSourceSetIds(), refactor all the usages, save some allocations
* Start caching CompositeSourceSetID properties to avoid excessive allocations
* Update integration tests on the latest revision with Knit version where the workaround is applied

Fixes #2897
  • Loading branch information
qwwdfsad authored Aug 14, 2023
1 parent 2fd8e90 commit 2269ac5
Show file tree
Hide file tree
Showing 19 changed files with 132 additions and 207 deletions.
24 changes: 2 additions & 22 deletions core/api/core.api
Original file line number Diff line number Diff line change
Expand Up @@ -863,10 +863,6 @@ public final class org/jetbrains/dokka/model/CompositeSourceSetID {
public fun toString ()Ljava/lang/String;
}

public final class org/jetbrains/dokka/model/CompositeSourceSetIDKt {
public static final fun plus (Lorg/jetbrains/dokka/DokkaSourceSetID;Lorg/jetbrains/dokka/DokkaSourceSetID;)Lorg/jetbrains/dokka/model/CompositeSourceSetID;
}

public final class org/jetbrains/dokka/model/Contravariance : org/jetbrains/dokka/model/Variance {
public fun <init> (Lorg/jetbrains/dokka/model/Bound;)V
public final fun component1 ()Lorg/jetbrains/dokka/model/Bound;
Expand Down Expand Up @@ -1400,40 +1396,24 @@ public final class org/jetbrains/dokka/model/DefinitelyNonNullable : org/jetbrai
public fun toString ()Ljava/lang/String;
}

public final class org/jetbrains/dokka/model/DisplaySourceSet : org/jetbrains/dokka/utilities/SelfRepresentingSingletonSet {
public final class org/jetbrains/dokka/model/DisplaySourceSet {
public fun <init> (Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet;)V
public fun <init> (Lorg/jetbrains/dokka/model/CompositeSourceSetID;Ljava/lang/String;Lorg/jetbrains/dokka/Platform;)V
public synthetic fun add (Ljava/lang/Object;)Z
public fun add (Lorg/jetbrains/dokka/model/DisplaySourceSet;)Z
public fun addAll (Ljava/util/Collection;)Z
public fun clear ()V
public final fun component1 ()Lorg/jetbrains/dokka/model/CompositeSourceSetID;
public final fun component2 ()Ljava/lang/String;
public final fun component3 ()Lorg/jetbrains/dokka/Platform;
public final fun contains (Ljava/lang/Object;)Z
public fun contains (Lorg/jetbrains/dokka/model/DisplaySourceSet;)Z
public synthetic fun contains (Lorg/jetbrains/dokka/utilities/SelfRepresentingSingletonSet;)Z
public fun containsAll (Ljava/util/Collection;)Z
public final fun copy (Lorg/jetbrains/dokka/model/CompositeSourceSetID;Ljava/lang/String;Lorg/jetbrains/dokka/Platform;)Lorg/jetbrains/dokka/model/DisplaySourceSet;
public static synthetic fun copy$default (Lorg/jetbrains/dokka/model/DisplaySourceSet;Lorg/jetbrains/dokka/model/CompositeSourceSetID;Ljava/lang/String;Lorg/jetbrains/dokka/Platform;ILjava/lang/Object;)Lorg/jetbrains/dokka/model/DisplaySourceSet;
public fun equals (Ljava/lang/Object;)Z
public final fun getName ()Ljava/lang/String;
public final fun getPlatform ()Lorg/jetbrains/dokka/Platform;
public fun getSize ()I
public final fun getSourceSetIDs ()Lorg/jetbrains/dokka/model/CompositeSourceSetID;
public fun hashCode ()I
public fun isEmpty ()Z
public fun iterator ()Ljava/util/Iterator;
public fun remove (Ljava/lang/Object;)Z
public fun removeAll (Ljava/util/Collection;)Z
public fun retainAll (Ljava/util/Collection;)Z
public final fun size ()I
public fun toArray ()[Ljava/lang/Object;
public fun toArray ([Ljava/lang/Object;)[Ljava/lang/Object;
public fun toString ()Ljava/lang/String;
}

public final class org/jetbrains/dokka/model/DisplaySourceSetKt {
public static final fun computeSourceSetIds (Ljava/lang/Iterable;)Ljava/util/Set;
public static final fun getSourceSetIDs (Ljava/lang/Iterable;)Ljava/util/List;
public static final fun toDisplaySourceSet (Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet;)Lorg/jetbrains/dokka/model/DisplaySourceSet;
public static final fun toDisplaySourceSets (Ljava/lang/Iterable;)Ljava/util/Set;
Expand Down
32 changes: 16 additions & 16 deletions core/src/main/kotlin/model/CompositeSourceSetID.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,30 @@ package org.jetbrains.dokka.model
import org.jetbrains.dokka.DokkaConfiguration
import org.jetbrains.dokka.DokkaSourceSetID

data class CompositeSourceSetID(
/**
* A unique composite key of multiple [DokkaSourceSetID] that identifies [DisplaySourceSet].
* Consists of multiple (non-zero) [DokkaSourceSetID] that the corresponding [DisplaySourceSet] was built from.
*
* Should not be constructed or copied outside of [DisplaySourceSet] instantiation.
*/
public data class CompositeSourceSetID(
private val children: Set<DokkaSourceSetID>
) {
constructor(sourceSetIDs: Iterable<DokkaSourceSetID>) : this(sourceSetIDs.toSet())
constructor(sourceSetId: DokkaSourceSetID) : this(setOf(sourceSetId))
public constructor(sourceSetIDs: Iterable<DokkaSourceSetID>) : this(sourceSetIDs.toSet())
public constructor(sourceSetId: DokkaSourceSetID) : this(setOf(sourceSetId))

init {
require(children.isNotEmpty()) { "Expected at least one source set id" }
}

val merged: DokkaSourceSetID
get() = children.sortedBy { it.scopeId + it.sourceSetName }.let { sortedChildren ->
DokkaSourceSetID(
scopeId = sortedChildren.joinToString(separator = "+") { it.scopeId },
sourceSetName = sortedChildren.joinToString(separator = "+") { it.sourceSetName }
)
}
public val merged: DokkaSourceSetID = children.sortedBy { it.scopeId + it.sourceSetName }.let { sortedChildren ->
DokkaSourceSetID(
scopeId = sortedChildren.joinToString(separator = "+") { it.scopeId },
sourceSetName = sortedChildren.joinToString(separator = "+") { it.sourceSetName }
)
}

val all: Set<DokkaSourceSetID>
get() = setOf(merged, *children.toTypedArray())
public val all: Set<DokkaSourceSetID> = setOf(merged, *children.toTypedArray())

operator fun contains(sourceSetId: DokkaSourceSetID): Boolean {
return sourceSetId in all
Expand All @@ -36,7 +40,3 @@ data class CompositeSourceSetID(
return copy(children = children + other)
}
}

operator fun DokkaSourceSetID.plus(other: DokkaSourceSetID): CompositeSourceSetID {
return CompositeSourceSetID(listOf(this, other))
}
55 changes: 40 additions & 15 deletions core/src/main/kotlin/model/DisplaySourceSet.kt
Original file line number Diff line number Diff line change
@@ -1,32 +1,57 @@
package org.jetbrains.dokka.model

import org.jetbrains.dokka.*
import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet
import org.jetbrains.dokka.DokkaSourceSetID
import org.jetbrains.dokka.Platform
import org.jetbrains.dokka.utilities.SelfRepresentingSingletonSet

/**
* TODO: fix the example (asymmetric equivalence relation with [Set]):
* ```
* val ds = DokkaSourceSetImpl(sourceSetID = DokkaSourceSetID("", "")).toDisplaySourceSet()
* println(setOf(ds) == ds) // true
* println(ds == setOf(ds)) // false
* ```
* Represents a final user-visible source set in the documentable model that is
* used to specify under which source sets/targets current signatures are available,
* can be used to filter in and out all available signatures under the specified source set,
* and, depending on the format, are rendered as "platform" selectors.
*
* E.g. HTML format renders display source sets as "bubbles" that later are used for filtering
* and informational purposes.
*
* [DisplaySourceSet]s typically have a one-to-one correspondence to the build system source sets,
* are created by the base plugin from [DokkaSourceSet] and never tweaked manually.
* [DisplaySourceSet] is uniquely identified by the corresponding [CompositeSourceSetID].
*
* @property sourceSetIDs unique stable id of the display source set.
* It is composite by definition, as it uniquely defines the source set and all nested source sets.
* Apart from names, it also contains a substitute to a full source set path in order to differentiate
* source sets with the same name in a stable manner.
* @property name corresponds to the name of the original [DokkaSourceSet]
* @property platform the platform of the source set. If the source set is a mix of multiple source sets
* that correspond to multiple KMP platforms, then it is [Platform.common]
*/
data class DisplaySourceSet(
public data class DisplaySourceSet(
val sourceSetIDs: CompositeSourceSetID,
val name: String,
val platform: Platform
) : SelfRepresentingSingletonSet<DisplaySourceSet> {
constructor(sourceSet: DokkaSourceSet) : this(
) {
public constructor(sourceSet: DokkaSourceSet) : this(
sourceSetIDs = CompositeSourceSetID(sourceSet.sourceSetID),
name = sourceSet.displayName,
platform = sourceSet.analysisPlatform
)
}

fun DokkaSourceSet.toDisplaySourceSet(): DisplaySourceSet = DisplaySourceSet(this)
/**
* Transforms the current [DokkaSourceSet] into [DisplaySourceSet],
* matching the corresponding subset of its properties to [DisplaySourceSet] properties.
*/
public fun DokkaSourceSet.toDisplaySourceSet(): DisplaySourceSet = DisplaySourceSet(this)

/**
* Transforms all the given [DokkaSourceSet]s into [DisplaySourceSet]s.
*/
public fun Iterable<DokkaSourceSet>.toDisplaySourceSets(): Set<DisplaySourceSet> =
map { it.toDisplaySourceSet() }.toSet()

fun Iterable<DokkaSourceSet>.toDisplaySourceSets(): Set<DisplaySourceSet> = map { it.toDisplaySourceSet() }.toSet()
@InternalDokkaApi
@Deprecated("Use computeSourceSetIds() and cache its results instead", replaceWith = ReplaceWith("computeSourceSetIds()"))
public val Iterable<DisplaySourceSet>.sourceSetIDs: List<DokkaSourceSetID> get() = this.flatMap { it.sourceSetIDs.all }

val Iterable<DisplaySourceSet>.sourceSetIDs: List<DokkaSourceSetID> get() = this.flatMap { it.sourceSetIDs.all }
@InternalDokkaApi
public fun Iterable<DisplaySourceSet>.computeSourceSetIds(): Set<DokkaSourceSetID> =
fold(hashSetOf()) { acc, set -> acc.addAll(set.sourceSetIDs.all); acc }
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package org.jetbrains.dokka.utilities
import org.jetbrains.dokka.InternalDokkaApi

@InternalDokkaApi
@Suppress("DEPRECATION_ERROR")
@Deprecated(message = "SelfRepresentingSingletonSet is an incorrect set implementation that breaks set invariants", level = DeprecationLevel.ERROR)
interface SelfRepresentingSingletonSet<T : SelfRepresentingSingletonSet<T>> : Set<T> {
override val size: Int get() = 1

Expand Down
6 changes: 5 additions & 1 deletion core/src/test/kotlin/model/CompositeSourceSetIDTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package model

import org.jetbrains.dokka.DokkaSourceSetID
import org.jetbrains.dokka.model.CompositeSourceSetID
import org.jetbrains.dokka.model.plus
import kotlin.test.*

class CompositeSourceSetIDTest {
Expand Down Expand Up @@ -65,4 +64,9 @@ class CompositeSourceSetIDTest {
"Expected all three source sets being merged in order"
)
}

operator fun DokkaSourceSetID.plus(other: DokkaSourceSetID): CompositeSourceSetID {
return CompositeSourceSetID(listOf(this, other))
}

}
10 changes: 4 additions & 6 deletions core/src/test/kotlin/model/DisplaySourceSetTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@ package model

import org.jetbrains.dokka.DokkaSourceSetID
import org.jetbrains.dokka.Platform
import org.jetbrains.dokka.model.CompositeSourceSetID
import org.jetbrains.dokka.model.DisplaySourceSet
import org.jetbrains.dokka.model.sourceSetIDs
import org.jetbrains.dokka.model.*
import kotlin.test.Test
import kotlin.test.assertFalse
import kotlin.test.assertTrue
Expand Down Expand Up @@ -44,17 +42,17 @@ class DisplaySourceSetTest {
)

assertFalse(
DokkaSourceSetID("m3", "s3") in listOf(contentSourceSet).sourceSetIDs,
DokkaSourceSetID("m3", "s3") in listOf(contentSourceSet).computeSourceSetIds(),
"Expected source set id not being contained in content source set"
)

assertTrue(
DokkaSourceSetID("m1", "s1") in listOf(contentSourceSet).sourceSetIDs,
DokkaSourceSetID("m1", "s1") in listOf(contentSourceSet).computeSourceSetIds(),
"Expected source set id being contained in content source set"
)

assertTrue(
DokkaSourceSetID("m1+m2", "s1+s2") in listOf(contentSourceSet).sourceSetIDs,
DokkaSourceSetID("m1+m2", "s1+s2") in listOf(contentSourceSet).computeSourceSetIds(),
"Expected merged source set being contained in content source set"
)
}
Expand Down
60 changes: 0 additions & 60 deletions core/src/test/kotlin/utilities/SelfRepresentingSingletonSetTest.kt

This file was deleted.

14 changes: 14 additions & 0 deletions integration-tests/gradle/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,17 @@ build.gradle.kts file -> "import gradle project".

Before importing: Make sure that you have dokka installed
locally (`./gradlew publishToMavenLocal`).

### To update git submodules

Integration tests have fixed git revision number, with the diff patch applied from the corresponding file (e.g. [`coroutines.diff`](projects/coroutines/coroutines.diff)).

In order to update:

* Checkout the project with the requered revision
- It's some state of the `master`
* Manually write the diff (or apply the existing one and tweak) to have the project buildable against locally published Dokka of version `for-integration-tests-SNAPSHOT`
* `git diff > $pathToProjectInDokka/project.diff`
* Go to `$pathToProjectInDokka`, `git fetch && git checkout $revisionNumber`
- Prior to that, ensure that you have your git submodules initialized
* Ensure that the corresponding `GradleIntegrationTest` passes locally and push
32 changes: 21 additions & 11 deletions integration-tests/gradle/projects/coroutines/coroutines.diff
Original file line number Diff line number Diff line change
@@ -1,17 +1,27 @@
diff --git a/build.gradle b/build.gradle
index 934d4c220..38321990e 100644
index e7d405e12..0ca2169fe 100644
--- a/build.gradle
+++ b/build.gradle
@@ -131,6 +131,7 @@ allprojects {
@@ -107,6 +107,9 @@ allprojects {
mavenLocal()
}
}
+ repositories {
+ mavenLocal()
+ }

ext.unpublished = unpublished

@@ -142,6 +145,7 @@ allprojects {
google()
mavenCentral()
CommunityProjectsBuild.addDevRepositoryIfEnabled(delegate, project)
+ mavenLocal()
}
}

diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts
index 785d13fdb..7fb19f467 100644
index ae54ad0f6..4655940a9 100644
--- a/buildSrc/build.gradle.kts
+++ b/buildSrc/build.gradle.kts
@@ -25,6 +25,7 @@ repositories {
Expand All @@ -20,8 +30,8 @@ index 785d13fdb..7fb19f467 100644
}
+ mavenLocal()
}
kotlinDslPluginOptions {

val gradleProperties = Properties().apply {
diff --git a/buildSrc/settings.gradle.kts b/buildSrc/settings.gradle.kts
index c2e859f65..43dc4f749 100644
--- a/buildSrc/settings.gradle.kts
Expand All @@ -34,14 +44,14 @@ index c2e859f65..43dc4f749 100644
}
}
diff --git a/gradle.properties b/gradle.properties
index db7cf099b..9c13c46fd 100644
index 3d9431be0..b60114bc2 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -14,7 +14,7 @@ atomicfu_version=0.18.5
knit_version=0.4.0
@@ -14,7 +14,7 @@ atomicfu_version=0.21.0
knit_version=0.5.0-Beta
html_version=0.7.2
lincheck_version=2.14.1
-dokka_version=1.7.20
lincheck_version=2.18.1
-dokka_version=1.8.10
+dokka_version=for-integration-tests-SNAPSHOT
byte_buddy_version=1.10.9
reactor_version=3.4.1
Expand Down
Loading

0 comments on commit 2269ac5

Please sign in to comment.