From c01e49eec9558736959d12820361624a3c3e41e5 Mon Sep 17 00:00:00 2001 From: Marcin Aman Date: Mon, 1 Mar 2021 11:57:30 +0100 Subject: Suppress tag support (#1742) * Suppress tag support * Support Hide tag in javadoc * Extract hide tag to be in separate plugin --- plugins/base/src/main/kotlin/DokkaBase.kt | 13 ++- .../ModuleAndPackageDocumentationReader.kt | 2 +- .../documentables/SuppressTagDocumentableFilter.kt | 12 +++ ...ByConfigurationDocumentableFilterTransformer.kt | 51 ++++++++++ ...SuppressedByTagDocumentableFilterTransformer.kt | 110 +++++++++++++++++++++ .../SuppressedDocumentableFilterTransformer.kt | 51 ---------- .../translators/psi/parsers/InheritDocResolver.kt | 4 +- .../translators/psi/parsers/JavadocParser.kt | 17 +++- .../kotlin/translators/psi/parsers/JavadocTag.kt | 2 +- 9 files changed, 201 insertions(+), 61 deletions(-) create mode 100644 plugins/base/src/main/kotlin/transformers/documentables/SuppressTagDocumentableFilter.kt create mode 100644 plugins/base/src/main/kotlin/transformers/documentables/SuppressedByConfigurationDocumentableFilterTransformer.kt create mode 100644 plugins/base/src/main/kotlin/transformers/documentables/SuppressedByTagDocumentableFilterTransformer.kt delete mode 100644 plugins/base/src/main/kotlin/transformers/documentables/SuppressedDocumentableFilterTransformer.kt (limited to 'plugins/base/src/main') diff --git a/plugins/base/src/main/kotlin/DokkaBase.kt b/plugins/base/src/main/kotlin/DokkaBase.kt index 4da2cb6e..2dbad3a7 100644 --- a/plugins/base/src/main/kotlin/DokkaBase.kt +++ b/plugins/base/src/main/kotlin/DokkaBase.kt @@ -67,7 +67,11 @@ class DokkaBase : DokkaPlugin() { } val suppressedDocumentableFilter by extending { - preMergeDocumentableTransformer providing ::SuppressedDocumentableFilterTransformer + preMergeDocumentableTransformer providing ::SuppressedByConfigurationDocumentableFilterTransformer + } + + val suppressedBySuppressTagDocumentableFilter by extending { + preMergeDocumentableTransformer providing ::SuppressTagDocumentableFilter } val documentableVisbilityFilter by extending { @@ -76,7 +80,12 @@ class DokkaBase : DokkaPlugin() { val emptyPackagesFilter by extending { preMergeDocumentableTransformer providing ::EmptyPackagesFilterTransformer order { - after(deprecatedDocumentableFilter, suppressedDocumentableFilter, documentableVisbilityFilter) + after( + deprecatedDocumentableFilter, + suppressedDocumentableFilter, + documentableVisbilityFilter, + suppressedBySuppressTagDocumentableFilter + ) } } diff --git a/plugins/base/src/main/kotlin/transformers/documentables/ModuleAndPackageDocumentationReader.kt b/plugins/base/src/main/kotlin/transformers/documentables/ModuleAndPackageDocumentationReader.kt index b74242c3..37903988 100644 --- a/plugins/base/src/main/kotlin/transformers/documentables/ModuleAndPackageDocumentationReader.kt +++ b/plugins/base/src/main/kotlin/transformers/documentables/ModuleAndPackageDocumentationReader.kt @@ -45,7 +45,7 @@ private class ContextModuleAndPackageDocumentationReader( ): SourceSetDependent { return sourceSets.associateWithNotNull { sourceSet -> val fragments = documentationFragments[sourceSet].orEmpty().filter(predicate) - val resolutionFacade = kotlinAnalysis?.get(sourceSet)?.facade + val resolutionFacade = kotlinAnalysis[sourceSet].facade val documentations = fragments.map { fragment -> parseModuleAndPackageDocumentation( context = ModuleAndPackageDocumentationParsingContext(context.logger, resolutionFacade), diff --git a/plugins/base/src/main/kotlin/transformers/documentables/SuppressTagDocumentableFilter.kt b/plugins/base/src/main/kotlin/transformers/documentables/SuppressTagDocumentableFilter.kt new file mode 100644 index 00000000..7efb23ab --- /dev/null +++ b/plugins/base/src/main/kotlin/transformers/documentables/SuppressTagDocumentableFilter.kt @@ -0,0 +1,12 @@ +package org.jetbrains.dokka.base.transformers.documentables + +import org.jetbrains.dokka.model.Documentable +import org.jetbrains.dokka.model.dfs +import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.model.doc.Suppress + +class SuppressTagDocumentableFilter(val dokkaContext: DokkaContext) : + SuppressedByTagDocumentableFilterTransformer(dokkaContext) { + override fun shouldBeSuppressed(d: Documentable): Boolean = + d.documentation.any { (_, docs) -> docs.dfs { it is Suppress } != null } +} \ No newline at end of file diff --git a/plugins/base/src/main/kotlin/transformers/documentables/SuppressedByConfigurationDocumentableFilterTransformer.kt b/plugins/base/src/main/kotlin/transformers/documentables/SuppressedByConfigurationDocumentableFilterTransformer.kt new file mode 100644 index 00000000..a013bfee --- /dev/null +++ b/plugins/base/src/main/kotlin/transformers/documentables/SuppressedByConfigurationDocumentableFilterTransformer.kt @@ -0,0 +1,51 @@ +package org.jetbrains.dokka.base.transformers.documentables + +import org.jetbrains.dokka.model.* +import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.transformers.documentation.PreMergeDocumentableTransformer +import org.jetbrains.dokka.transformers.documentation.perPackageOptions +import org.jetbrains.dokka.transformers.documentation.source +import org.jetbrains.dokka.transformers.documentation.sourceSet +import java.io.File + +class SuppressedByConfigurationDocumentableFilterTransformer(val context: DokkaContext) : PreMergeDocumentableTransformer { + override fun invoke(modules: List): List { + return modules.mapNotNull(::filterModule) + } + + private fun filterModule(module: DModule): DModule? { + val packages = module.packages.mapNotNull { pkg -> filterPackage(pkg) } + return when { + packages == module.packages -> module + packages.isEmpty() -> null + else -> module.copy(packages = packages) + } + } + + private fun filterPackage(pkg: DPackage): DPackage? { + val options = perPackageOptions(pkg) + if (options?.suppress == true) { + return null + } + + val filteredChildren = pkg.children.filterNot(::isSuppressed) + return when { + filteredChildren == pkg.children -> pkg + filteredChildren.isEmpty() -> null + else -> pkg.copy( + functions = filteredChildren.filterIsInstance(), + classlikes = filteredChildren.filterIsInstance(), + typealiases = filteredChildren.filterIsInstance(), + properties = filteredChildren.filterIsInstance() + ) + } + } + + private fun isSuppressed(documentable: Documentable): Boolean { + if (documentable !is WithSources) return false + val sourceFile = File(source(documentable).path).absoluteFile + return sourceSet(documentable).suppressedFiles.any { suppressedFile -> + sourceFile.startsWith(suppressedFile.absoluteFile) + } + } +} diff --git a/plugins/base/src/main/kotlin/transformers/documentables/SuppressedByTagDocumentableFilterTransformer.kt b/plugins/base/src/main/kotlin/transformers/documentables/SuppressedByTagDocumentableFilterTransformer.kt new file mode 100644 index 00000000..f40abe70 --- /dev/null +++ b/plugins/base/src/main/kotlin/transformers/documentables/SuppressedByTagDocumentableFilterTransformer.kt @@ -0,0 +1,110 @@ +package org.jetbrains.dokka.base.transformers.documentables + +import org.jetbrains.dokka.model.* +import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.transformers.documentation.PreMergeDocumentableTransformer + +abstract class SuppressedByTagDocumentableFilterTransformer(val context: DokkaContext) : PreMergeDocumentableTransformer { + override fun invoke(modules: List): List = + modules.map { module -> + val (documentable, wasChanged) = processModule(module) + documentable.takeIf { wasChanged } ?: module + } + + abstract fun shouldBeSuppressed(d: Documentable): Boolean + + private fun processModule(module: DModule): DocumentableWithChanges { + val afterProcessing = module.packages.map { processPackage(it) } + val processedModule = module.takeIf { afterProcessing.none { it.changed } } + ?: module.copy(packages = afterProcessing.mapNotNull { it.documentable }) + return DocumentableWithChanges(processedModule, afterProcessing.any { it.changed }) + } + + private fun processPackage(dPackage: DPackage): DocumentableWithChanges { + val classlikes = dPackage.classlikes.map { processClassLike(it) } + val typeAliases = dPackage.typealiases.map { processMember(it) } + val functions = dPackage.functions.map { processMember(it) } + val properies = dPackage.properties.map { processMember(it) } + + val wasChanged = (classlikes + typeAliases + functions + properies).any { it.changed } + return (dPackage.takeIf { !wasChanged } ?: dPackage.copy( + classlikes = classlikes.mapNotNull { it.documentable }, + typealiases = typeAliases.mapNotNull { it.documentable }, + functions = functions.mapNotNull { it.documentable }, + properties = properies.mapNotNull { it.documentable } + )).let { processedPackage -> DocumentableWithChanges(processedPackage, wasChanged) } + } + + private fun processClassLike(classlike: DClasslike): DocumentableWithChanges { + if (shouldBeSuppressed(classlike)) return DocumentableWithChanges.filteredDocumentable() + + val functions = classlike.functions.map { processMember(it) } + val classlikes = classlike.classlikes.map { processClassLike(it) } + val properties = classlike.properties.map { processMember(it) } + val companion = (classlike as? WithCompanion)?.companion?.let { processClassLike(it) } + + val wasClasslikeChanged = (functions + classlikes + properties).any { it.changed } || companion?.changed == true + return when (classlike) { + is DClass -> { + val constructors = classlike.constructors.map { processMember(it) } + val wasClassChange = + wasClasslikeChanged || constructors.any { it.changed } + (classlike.takeIf { !wasClassChange } ?: classlike.copy( + functions = functions.mapNotNull { it.documentable }, + classlikes = classlikes.mapNotNull { it.documentable }, + properties = properties.mapNotNull { it.documentable }, + constructors = constructors.mapNotNull { it.documentable }, + companion = companion?.documentable as? DObject + )).let { DocumentableWithChanges(it, wasClassChange) } + } + is DInterface -> (classlike.takeIf { !wasClasslikeChanged } ?: classlike.copy( + functions = functions.mapNotNull { it.documentable }, + classlikes = classlikes.mapNotNull { it.documentable }, + properties = properties.mapNotNull { it.documentable }, + companion = companion?.documentable as? DObject + )).let { DocumentableWithChanges(it, wasClasslikeChanged) } + is DObject -> (classlike.takeIf { !wasClasslikeChanged } ?: classlike.copy( + functions = functions.mapNotNull { it.documentable }, + classlikes = classlikes.mapNotNull { it.documentable }, + properties = properties.mapNotNull { it.documentable }, + )).let { DocumentableWithChanges(it, wasClasslikeChanged) } + is DAnnotation -> { + val constructors = classlike.constructors.map { processMember(it) } + val wasClassChange = + wasClasslikeChanged || constructors.any { it.changed } + (classlike.takeIf { !wasClassChange } ?: classlike.copy( + functions = functions.mapNotNull { it.documentable }, + classlikes = classlikes.mapNotNull { it.documentable }, + properties = properties.mapNotNull { it.documentable }, + constructors = constructors.mapNotNull { it.documentable }, + companion = companion?.documentable as? DObject + )).let { DocumentableWithChanges(it, wasClassChange) } + } + is DEnum -> { + val constructors = classlike.constructors.map { processMember(it) } + val entries = classlike.entries.map { processMember(it) } + val wasClassChange = + wasClasslikeChanged || (constructors + entries).any { it.changed } + (classlike.takeIf { !wasClassChange } ?: classlike.copy( + functions = functions.mapNotNull { it.documentable }, + classlikes = classlikes.mapNotNull { it.documentable }, + properties = properties.mapNotNull { it.documentable }, + constructors = constructors.mapNotNull { it.documentable }, + companion = companion?.documentable as? DObject, + entries = entries.mapNotNull { it.documentable } + )).let { DocumentableWithChanges(it, wasClassChange) } + } + } + } + + private fun processMember(member: T): DocumentableWithChanges = + if (shouldBeSuppressed(member)) DocumentableWithChanges.filteredDocumentable() + else DocumentableWithChanges(member, false) + + private data class DocumentableWithChanges(val documentable: T?, val changed: Boolean = false) { + companion object { + fun filteredDocumentable(): DocumentableWithChanges = + DocumentableWithChanges(null, true) + } + } +} \ No newline at end of file diff --git a/plugins/base/src/main/kotlin/transformers/documentables/SuppressedDocumentableFilterTransformer.kt b/plugins/base/src/main/kotlin/transformers/documentables/SuppressedDocumentableFilterTransformer.kt deleted file mode 100644 index b066e69b..00000000 --- a/plugins/base/src/main/kotlin/transformers/documentables/SuppressedDocumentableFilterTransformer.kt +++ /dev/null @@ -1,51 +0,0 @@ -package org.jetbrains.dokka.base.transformers.documentables - -import org.jetbrains.dokka.model.* -import org.jetbrains.dokka.plugability.DokkaContext -import org.jetbrains.dokka.transformers.documentation.PreMergeDocumentableTransformer -import org.jetbrains.dokka.transformers.documentation.perPackageOptions -import org.jetbrains.dokka.transformers.documentation.source -import org.jetbrains.dokka.transformers.documentation.sourceSet -import java.io.File - -class SuppressedDocumentableFilterTransformer(val context: DokkaContext) : PreMergeDocumentableTransformer { - override fun invoke(modules: List): List { - return modules.mapNotNull(::filterModule) - } - - private fun filterModule(module: DModule): DModule? { - val packages = module.packages.mapNotNull { pkg -> filterPackage(pkg) } - return when { - packages == module.packages -> module - packages.isEmpty() -> null - else -> module.copy(packages = packages) - } - } - - private fun filterPackage(pkg: DPackage): DPackage? { - val options = perPackageOptions(pkg) - if (options?.suppress == true) { - return null - } - - val filteredChildren = pkg.children.filterNot(::isSuppressed) - return when { - filteredChildren == pkg.children -> pkg - filteredChildren.isEmpty() -> null - else -> pkg.copy( - functions = filteredChildren.filterIsInstance(), - classlikes = filteredChildren.filterIsInstance(), - typealiases = filteredChildren.filterIsInstance(), - properties = filteredChildren.filterIsInstance() - ) - } - } - - private fun isSuppressed(documentable: Documentable): Boolean { - if (documentable !is WithSources) return false - val sourceFile = File(source(documentable).path).absoluteFile - return sourceSet(documentable).suppressedFiles.any { suppressedFile -> - sourceFile.startsWith(suppressedFile.absoluteFile) - } - } -} diff --git a/plugins/base/src/main/kotlin/translators/psi/parsers/InheritDocResolver.kt b/plugins/base/src/main/kotlin/translators/psi/parsers/InheritDocResolver.kt index c2fb6fb4..21c2c72a 100644 --- a/plugins/base/src/main/kotlin/translators/psi/parsers/InheritDocResolver.kt +++ b/plugins/base/src/main/kotlin/translators/psi/parsers/InheritDocResolver.kt @@ -11,7 +11,7 @@ import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull internal data class CommentResolutionContext( val comment: PsiDocComment, - val tag: JavadocTag, + val tag: JavadocTag?, val name: String? = null, val parameterIndex: Int? = null, ) @@ -25,7 +25,7 @@ internal class InheritDocResolver( JavadocTag.PARAM -> context.parameterIndex?.let { paramIndex -> resolveParamTag(context.comment, paramIndex) } JavadocTag.DEPRECATED -> resolveGenericTag(context.comment, JavadocTag.DESCRIPTION) JavadocTag.SEE -> emptyList() - else -> resolveGenericTag(context.comment, context.tag) + else -> context.tag?.let { tag -> resolveGenericTag(context.comment, tag) } } private fun resolveGenericTag(currentElement: PsiDocComment, tag: JavadocTag): List = diff --git a/plugins/base/src/main/kotlin/translators/psi/parsers/JavadocParser.kt b/plugins/base/src/main/kotlin/translators/psi/parsers/JavadocParser.kt index 96c62b36..a02bceac 100644 --- a/plugins/base/src/main/kotlin/translators/psi/parsers/JavadocParser.kt +++ b/plugins/base/src/main/kotlin/translators/psi/parsers/JavadocParser.kt @@ -12,6 +12,7 @@ import org.jetbrains.dokka.analysis.from import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.model.doc.* import org.jetbrains.dokka.model.doc.Deprecated +import org.jetbrains.dokka.model.doc.Suppress import org.jetbrains.dokka.utilities.DokkaLogger import org.jetbrains.dokka.utilities.enumValueOrNull import org.jetbrains.kotlin.idea.refactoring.fqName.getKotlinFqName @@ -118,7 +119,15 @@ class JavadocParser( else -> null //TODO https://github.com/Kotlin/dokka/issues/1618 } - } + } ?: CustomTagWrapper( + wrapTagIfNecessary( + convertJavadocElements( + tag.contentElementsWithSiblingIfNeeded(), + context = CommentResolutionContext(docComment, null) + ) + ), + tag.name + ) private fun wrapTagIfNecessary(list: List): CustomDocTag = if (list.size == 1 && (list.first() as? CustomDocTag)?.name == MarkdownElementTypes.MARKDOWN_FILE.name) @@ -148,14 +157,14 @@ class JavadocParser( } private data class ParserState( - val currentJavadocTag: JavadocTag, + val currentJavadocTag: JavadocTag?, val previousElement: PsiElement? = null, val openPreTags: Int = 0, val closedPreTags: Int = 0 ) private data class ParsingResult(val newState: ParserState, val parsedLine: String? = null) { - constructor(tag: JavadocTag) : this(ParserState(tag)) + constructor(tag: JavadocTag?) : this(ParserState(tag)) operator fun plus(other: ParsingResult): ParsingResult = ParsingResult( @@ -267,7 +276,7 @@ class JavadocParser( private fun convertInlineDocTag( tag: PsiInlineDocTag, - javadocTag: JavadocTag, + javadocTag: JavadocTag?, context: CommentResolutionContext ) = when (tag.name) { diff --git a/plugins/base/src/main/kotlin/translators/psi/parsers/JavadocTag.kt b/plugins/base/src/main/kotlin/translators/psi/parsers/JavadocTag.kt index 8ea39453..869ced30 100644 --- a/plugins/base/src/main/kotlin/translators/psi/parsers/JavadocTag.kt +++ b/plugins/base/src/main/kotlin/translators/psi/parsers/JavadocTag.kt @@ -1,7 +1,7 @@ package org.jetbrains.dokka.base.translators.psi.parsers internal enum class JavadocTag { - PARAM, THROWS, RETURN, AUTHOR, SEE, DEPRECATED, EXCEPTION, + PARAM, THROWS, RETURN, AUTHOR, SEE, DEPRECATED, EXCEPTION, HIDE, /** * Artificial tag created to handle tag-less section -- cgit