Skip to content

Commit

Permalink
Do not use finalize
Browse files Browse the repository at this point in the history
Refactor
  • Loading branch information
vmishenev committed Dec 1, 2022
1 parent 23746f5 commit d071060
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 57 deletions.
Expand Up @@ -8,30 +8,48 @@ import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSourceLocation
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.cli.common.messages.MessageRenderer
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import java.io.Closeable
import java.io.File

internal fun createEnvironmentAndFacade(
logger: DokkaLogger,
sourceSets: List<DokkaConfiguration.DokkaSourceSet>,
sourceSet: DokkaConfiguration.DokkaSourceSet,
analysisConfiguration: DokkaAnalysisConfiguration
): EnvironmentAndFacade =
AnalysisEnvironment(DokkaMessageCollector(logger), sourceSet.analysisPlatform).run {
if (analysisPlatform == Platform.jvm) {
configureJdkClasspathRoots()
}
): EnvironmentAndFacade {
val parentSourceSets = sourceSets.filter { it.sourceSetID in sourceSet.dependentSourceSets }
val classpath = sourceSet.classpath + parentSourceSets.flatMap { it.classpath }
val sources = sourceSet.sourceRoots + parentSourceSets.flatMap { it.sourceRoots }

val parentSourceSets = sourceSets.filter { it.sourceSetID in sourceSet.dependentSourceSets }
addClasspath(sourceSet.classpath + parentSourceSets.flatMap { it.classpath })
return createEnvironmentAndFacade(
logger = logger,
classpath = classpath,
sourceRoots = sources,
sourceSet = sourceSet,
analysisConfiguration = analysisConfiguration
)
}

addSources(sourceSet.sourceRoots + parentSourceSets.flatMap { it.sourceRoots })
internal fun createEnvironmentAndFacade(
logger: DokkaLogger,
classpath: List<File>,
sourceRoots: Set<File>,
sourceSet: DokkaConfiguration.DokkaSourceSet,
analysisConfiguration: DokkaAnalysisConfiguration
) = AnalysisEnvironment(DokkaMessageCollector(logger), sourceSet.analysisPlatform).run {
if (analysisPlatform == Platform.jvm) {
configureJdkClasspathRoots()
}
addClasspath(classpath)
addSources(sourceRoots)

loadLanguageVersionSettings(sourceSet.languageVersion, sourceSet.apiVersion)
loadLanguageVersionSettings(sourceSet.languageVersion, sourceSet.apiVersion)

val environment = createCoreEnvironment()
val environment = createCoreEnvironment()

val (facade, _) = createResolutionFacade(environment, analysisConfiguration.ignoreCommonBuiltIns)
EnvironmentAndFacade(environment, facade, this)
}
val (facade, _) = createResolutionFacade(environment, analysisConfiguration.ignoreCommonBuiltIns)
EnvironmentAndFacade(environment, facade, this)
}

class DokkaMessageCollector(private val logger: DokkaLogger) : MessageCollector {
override fun clear() {
Expand All @@ -51,10 +69,21 @@ class DokkaMessageCollector(private val logger: DokkaLogger) : MessageCollector
}

// It is not data class due to ill-defined equals
class EnvironmentAndFacade(val environment: KotlinCoreEnvironment, val facade: DokkaResolutionFacade, private val analysisEnvironment: AnalysisEnvironment) {
class EnvironmentAndFacade(
environment: KotlinCoreEnvironment,
facade: DokkaResolutionFacade,
private val analysisEnvironment: AnalysisEnvironment
) : Closeable {
private var isClosed: Boolean = false
val environment: KotlinCoreEnvironment = environment
get() = field.takeUnless { isClosed } ?: throw IllegalStateException("AnalysisEnvironment is already closed")
val facade: DokkaResolutionFacade = facade
get() = field.takeUnless { isClosed } ?: throw IllegalStateException("AnalysisEnvironment is already closed")

operator fun component1() = environment
operator fun component2() = facade
protected fun finalize() {
override fun close() {
isClosed = true
analysisEnvironment.dispose()
}
}
Expand Up @@ -7,8 +7,13 @@ import org.jetbrains.dokka.DokkaSourceSetID
import org.jetbrains.dokka.model.SourceSetDependent
import org.jetbrains.dokka.plugability.DokkaContext
import org.jetbrains.dokka.utilities.DokkaLogger
import java.io.Closeable

fun KotlinAnalysis(sourceSets: List<DokkaSourceSet>, logger: DokkaLogger, analysisConfiguration: DokkaAnalysisConfiguration = DokkaAnalysisConfiguration()): KotlinAnalysis {
fun KotlinAnalysis(
sourceSets: List<DokkaSourceSet>,
logger: DokkaLogger,
analysisConfiguration: DokkaAnalysisConfiguration = DokkaAnalysisConfiguration()
): KotlinAnalysis {
val environments = sourceSets.associateWith { sourceSet ->
createEnvironmentAndFacade(
logger = logger,
Expand All @@ -17,10 +22,30 @@ fun KotlinAnalysis(sourceSets: List<DokkaSourceSet>, logger: DokkaLogger, analys
analysisConfiguration = analysisConfiguration
)
}

return KotlinAnalysisImpl(environments)
}

fun KotlinAnalysisForSamples(
sourceSets: List<DokkaSourceSet>,
logger: DokkaLogger,
defaultKotlinAnalysis: KotlinAnalysis,
analysisConfiguration: DokkaAnalysisConfiguration = DokkaAnalysisConfiguration()
): KotlinAnalysis {
val environments = sourceSets
.filter { it.samples.isNotEmpty() }
.associateWith { sourceSet ->
createEnvironmentAndFacade(
logger = logger,
classpath = sourceSet.classpath,
sourceRoots = sourceSet.samples,
sourceSet = sourceSet,
analysisConfiguration = analysisConfiguration
)
}

return KotlinAnalysisImpl(environments, defaultKotlinAnalysis)
}

class DokkaAnalysisConfiguration(
/**
* Only for common platform ignore BuiltIns for StdLib since it can cause a conflict
Expand All @@ -34,20 +59,30 @@ class DokkaAnalysisConfiguration(
)
fun KotlinAnalysis(context: DokkaContext): KotlinAnalysis = KotlinAnalysis(context.configuration.sourceSets, context.logger)

interface KotlinAnalysis : SourceSetDependent<EnvironmentAndFacade> {
interface KotlinAnalysis : SourceSetDependent<EnvironmentAndFacade>, Closeable {
override fun get(key: DokkaSourceSet): EnvironmentAndFacade
operator fun get(sourceSetID: DokkaSourceSetID): EnvironmentAndFacade
}

/**
* It does not close [defaultKotlinAnalysis].
*/
internal class KotlinAnalysisImpl(
private val environments: SourceSetDependent<EnvironmentAndFacade>
private val environments: SourceSetDependent<EnvironmentAndFacade>,
private val defaultKotlinAnalysis: KotlinAnalysis? = null
) : KotlinAnalysis, SourceSetDependent<EnvironmentAndFacade> by environments {

override fun get(key: DokkaSourceSet): EnvironmentAndFacade {
return environments[key] ?: throw IllegalStateException("Missing EnvironmentAndFacade for sourceSet $key")
return environments[key] ?: defaultKotlinAnalysis?.get(key)
?: throw IllegalStateException("Missing EnvironmentAndFacade for sourceSet $key")
}

override fun get(sourceSetID: DokkaSourceSetID): EnvironmentAndFacade {
return environments.entries.first { (sourceSet, _) -> sourceSet.sourceSetID == sourceSetID }.value
return environments.entries.firstOrNull { (sourceSet, _) -> sourceSet.sourceSetID == sourceSetID }?.value
?: defaultKotlinAnalysis?.get(sourceSetID)
?: throw IllegalStateException("Missing EnvironmentAndFacade for sourceSetID $sourceSetID")
}
}
override fun close() {
environments.values.forEach(EnvironmentAndFacade::close)
}
}
1 change: 1 addition & 0 deletions plugins/base/api/base.api
Expand Up @@ -13,6 +13,7 @@ public final class org/jetbrains/dokka/base/DokkaBase : org/jetbrains/dokka/plug
public final fun getDefaultTabSortingStrategy ()Lorg/jetbrains/dokka/plugability/Extension;
public final fun getDeprecatedDocumentableFilter ()Lorg/jetbrains/dokka/plugability/Extension;
public final fun getDescriptorToDocumentableTranslator ()Lorg/jetbrains/dokka/plugability/Extension;
public final fun getDisposeKotlinAnalysisPostAction ()Lorg/jetbrains/dokka/plugability/Extension;
public final fun getDocTagToContentConverter ()Lorg/jetbrains/dokka/plugability/Extension;
public final fun getDocumentableMerger ()Lorg/jetbrains/dokka/plugability/Extension;
public final fun getDocumentableToPageTranslator ()Lorg/jetbrains/dokka/plugability/Extension;
Expand Down
Expand Up @@ -53,6 +53,8 @@ class BaseDokkaTestGenerator(
singleModuleGeneration.render(transformedPages)
renderingStage(transformedPages, context)

singleModuleGeneration.runPostActions()

singleModuleGeneration.reportAfterRendering()
}
}
Expand Down
7 changes: 6 additions & 1 deletion plugins/base/src/main/kotlin/DokkaBase.kt
Expand Up @@ -36,7 +36,8 @@ import org.jetbrains.dokka.base.translators.descriptors.ExternalClasslikesTransl
import org.jetbrains.dokka.base.translators.descriptors.ExternalDocumentablesProvider
import org.jetbrains.dokka.base.utils.NoopIntellijLoggerFactory
import org.jetbrains.dokka.plugability.DokkaPlugin
import org.jetbrains.dokka.plugability.configuration
import org.jetbrains.dokka.plugability.querySingle
import org.jetbrains.dokka.renderers.PostAction
import org.jetbrains.dokka.transformers.documentation.PreMergeDocumentableTransformer
import org.jetbrains.dokka.transformers.pages.PageTransformer

Expand Down Expand Up @@ -280,6 +281,10 @@ class DokkaBase : DokkaPlugin() {
externalClasslikesTranslator providing ::DefaultDescriptorToDocumentableTranslator
}

val disposeKotlinAnalysisPostAction by extending {
CoreExtensions.postActions with PostAction { this@DokkaBase.querySingle { kotlinAnalysis }.close() }
}

private companion object {
init {
// Suppress messages emitted by the IntelliJ logger since
Expand Down
Expand Up @@ -2,11 +2,7 @@ package org.jetbrains.dokka.base.transformers.pages.samples

import com.intellij.psi.PsiElement
import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet
import org.jetbrains.dokka.Platform
import org.jetbrains.dokka.analysis.AnalysisEnvironment
import org.jetbrains.dokka.analysis.DokkaMessageCollector
import org.jetbrains.dokka.analysis.DokkaResolutionFacade
import org.jetbrains.dokka.analysis.EnvironmentAndFacade
import org.jetbrains.dokka.analysis.*
import org.jetbrains.dokka.base.DokkaBase
import org.jetbrains.dokka.base.renderers.sourceSets
import org.jetbrains.dokka.links.DRI
Expand All @@ -29,42 +25,27 @@ abstract class SamplesTransformer(val context: DokkaContext) : PageTransformer {
abstract fun processImports(psiElement: PsiElement): String

final override fun invoke(input: RootPageNode): RootPageNode {
val analysis = setUpAnalysis(context)
val kotlinPlaygroundScript =
"<script src=\"https://unpkg.com/kotlin-playground@1\"></script>"

return input.transformContentPagesTree { page ->
val samples = (page as? WithDocumentables)?.documentables?.flatMap {
it.documentation.entries.flatMap { entry ->
entry.value.children.filterIsInstance<Sample>().map { entry.key to it }
val analysis = KotlinAnalysisForSamples(sourceSets = context.configuration.sourceSets,
logger = context.logger,
defaultKotlinAnalysis = context.plugin<DokkaBase>().querySingle { kotlinAnalysis })

val kotlinPlaygroundScript = "<script src=\"https://unpkg.com/kotlin-playground@1\"></script>"

return analysis.use {
input.transformContentPagesTree { page ->
val samples = (page as? WithDocumentables)?.documentables?.flatMap {
it.documentation.entries.flatMap { entry ->
entry.value.children.filterIsInstance<Sample>().map { entry.key to it }
}
}
}

samples?.fold(page as ContentPage) { acc, (sampleSourceSet, sample) ->
samples?.fold(page as ContentPage) { acc, (sampleSourceSet, sample) ->
acc.modified(
content = acc.content.addSample(page, sampleSourceSet, sample.name, analysis),
content = acc.content.addSample(page, sampleSourceSet, sample.name, it),
embeddedResources = acc.embeddedResources + kotlinPlaygroundScript
)
} ?: page
}
}

private fun setUpAnalysis(context: DokkaContext) = context.configuration.sourceSets.associateWith { sourceSet ->
if (sourceSet.samples.isEmpty()) context.plugin<DokkaBase>()
.querySingle { kotlinAnalysis }[sourceSet] // from sourceSet.sourceRoots
else AnalysisEnvironment(DokkaMessageCollector(context.logger), sourceSet.analysisPlatform).run {
if (analysisPlatform == Platform.jvm) {
configureJdkClasspathRoots()
}
sourceSet.classpath.forEach(::addClasspath)

addSources(sourceSet.samples.toList())

loadLanguageVersionSettings(sourceSet.languageVersion, sourceSet.apiVersion)

val environment = createCoreEnvironment()
val (facade, _) = createResolutionFacade(environment)
EnvironmentAndFacade(environment, facade, this)
}
}

Expand Down

0 comments on commit d071060

Please sign in to comment.