Skip to content

Commit

Permalink
Suppress tag support (#1742)
Browse files Browse the repository at this point in the history
* Suppress tag support

* Support Hide tag in javadoc

* Extract hide tag to be in separate plugin
  • Loading branch information
MarcinAman authored Mar 1, 2021
1 parent 201a978 commit c01e49e
Show file tree
Hide file tree
Showing 19 changed files with 459 additions and 12 deletions.
8 changes: 8 additions & 0 deletions docs/src/doc/docs/user_guide/android-plugin/android-plugin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Android documentationn plugin

Android documentation plugin aims to improve the documentation on android platform.

### Features:

* `@hide` support - `@hide` javadoc tag is an equivalent of `@suppress` tag in kdoc. It hides certain entry from being
displayed in the documentation.
1 change: 1 addition & 0 deletions docs/src/doc/docs/user_guide/introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Currently maintained plugins are:
* `jekyll-plugin` - configures `Jekyll` output format
* `javadoc-plugin` - configures `Javadoc` output format, automatically applies `kotlin-as-java-plugin`
* `kotlin-as-java-plugin` - translates Kotlin definitions to Java
* `android-documentation-plugin` - provides android specific enhancements like `@hide` support

Please see the usage instructions for each build system on how to add plugins to Dokka.

Expand Down
1 change: 1 addition & 0 deletions docs/src/doc/mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ nav:
- Maven: user_guide/maven/usage.md
- Command line: user_guide/cli/usage.md
- Html frontend: user_guide/base-specific/frontend.md
- Android plugin: user_guide/android-plugin/android-plugin.md
- Plugin development:
- Introduction: developer_guide/introduction.md
- Data model: developer_guide/data_model.md
Expand Down
11 changes: 11 additions & 0 deletions plugins/android-documentation/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import org.jetbrains.registerDokkaArtifactPublication

dependencies {
implementation(project(":plugins:base"))
testImplementation(project(":plugins:base"))
testImplementation(project(":plugins:base:base-test-utils"))
}

registerDokkaArtifactPublication("androidDocumentationPlugin") {
artifactId = "android-documentation-plugin"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.jetbrains.dokka.android

import org.jetbrains.dokka.android.transformers.HideTagDocumentableFilter
import org.jetbrains.dokka.base.DokkaBase
import org.jetbrains.dokka.plugability.DokkaPlugin

class AndroidDocumentationPlugin : DokkaPlugin() {
private val dokkaBase by lazy { plugin<DokkaBase>() }

val suppressedByHideTagDocumentableFilter by extending {
dokkaBase.preMergeDocumentableTransformer providing ::HideTagDocumentableFilter order { before(dokkaBase.emptyPackagesFilter) }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.jetbrains.dokka.android.transformers

import org.jetbrains.dokka.base.transformers.documentables.SuppressedByTagDocumentableFilterTransformer
import org.jetbrains.dokka.model.Documentable
import org.jetbrains.dokka.model.dfs
import org.jetbrains.dokka.model.doc.CustomTagWrapper
import org.jetbrains.dokka.plugability.DokkaContext

class HideTagDocumentableFilter(val dokkaContext: DokkaContext) :
SuppressedByTagDocumentableFilterTransformer(dokkaContext) {
override fun shouldBeSuppressed(d: Documentable): Boolean =
d.documentation.any { (_, docs) -> docs.dfs { it is CustomTagWrapper && it.name.trim() == "hide" } != null }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
org.jetbrains.dokka.android.AndroidDocumentationPlugin
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package transformers

import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest
import org.jetbrains.dokka.model.DClass
import kotlin.test.assertEquals
import org.junit.jupiter.api.Test

class HideTagDocumentableFilterTest : BaseAbstractTest() {
private val configuration = dokkaConfiguration {
sourceSets {
sourceSet {
sourceRoots = listOf("src")
}
}
}


@Test
fun `should work as hide in java with functions`() {
testInline(
"""
|/src/suppressed/Testing.java
|package testing;
|
|public class Testing {
| /**
| * @hide
| */
| public void shouldNotBeVisible() { }
|}
""".trimIndent(), configuration
) {
documentablesFirstTransformationStep = { modules ->
val testingClass = modules.flatMap { it.packages }.flatMap { it.classlikes }.single() as DClass
assertEquals(0, testingClass.functions.size)
}
}
}

@Test
fun `should work as hide in java with classes`() {
testInline(
"""
|/src/suppressed/Suppressed.java
|package testing;
|
|/**
| * @hide
| */
|public class Suppressed {
|}
|/src/suppressed/Visible.java
|package testing;
|
|/**
| * Another docs
| * @undeprecate
| */
|public class Visible {
|}
""".trimIndent(), configuration
) {
documentablesFirstTransformationStep = { modules ->
val classes = modules.flatMap { it.packages }.flatMap { it.classlikes }.map { it.name }
assertEquals(listOf("Visible"), classes)
}
}
}


}
13 changes: 11 additions & 2 deletions plugins/base/src/main/kotlin/DokkaBase.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -76,7 +80,12 @@ class DokkaBase : DokkaPlugin() {

val emptyPackagesFilter by extending {
preMergeDocumentableTransformer providing ::EmptyPackagesFilterTransformer order {
after(deprecatedDocumentableFilter, suppressedDocumentableFilter, documentableVisbilityFilter)
after(
deprecatedDocumentableFilter,
suppressedDocumentableFilter,
documentableVisbilityFilter,
suppressedBySuppressTagDocumentableFilter
)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ private class ContextModuleAndPackageDocumentationReader(
): SourceSetDependent<DocumentationNode> {
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),
Expand Down
Original file line number Diff line number Diff line change
@@ -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 }
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import org.jetbrains.dokka.transformers.documentation.source
import org.jetbrains.dokka.transformers.documentation.sourceSet
import java.io.File

class SuppressedDocumentableFilterTransformer(val context: DokkaContext) : PreMergeDocumentableTransformer {
class SuppressedByConfigurationDocumentableFilterTransformer(val context: DokkaContext) : PreMergeDocumentableTransformer {
override fun invoke(modules: List<DModule>): List<DModule> {
return modules.mapNotNull(::filterModule)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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<DModule>): List<DModule> =
modules.map { module ->
val (documentable, wasChanged) = processModule(module)
documentable.takeIf { wasChanged } ?: module
}

abstract fun shouldBeSuppressed(d: Documentable): Boolean

private fun processModule(module: DModule): DocumentableWithChanges<DModule> {
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<DPackage> {
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<DClasslike> {
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 <T : Documentable> processMember(member: T): DocumentableWithChanges<T> =
if (shouldBeSuppressed(member)) DocumentableWithChanges.filteredDocumentable()
else DocumentableWithChanges(member, false)

private data class DocumentableWithChanges<T : Documentable>(val documentable: T?, val changed: Boolean = false) {
companion object {
fun <T : Documentable> filteredDocumentable(): DocumentableWithChanges<T> =
DocumentableWithChanges(null, true)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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,
)
Expand All @@ -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<PsiElement> =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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<DocTag>): CustomDocTag =
if (list.size == 1 && (list.first() as? CustomDocTag)?.name == MarkdownElementTypes.MARKDOWN_FILE.name)
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -267,7 +276,7 @@ class JavadocParser(

private fun convertInlineDocTag(
tag: PsiInlineDocTag,
javadocTag: JavadocTag,
javadocTag: JavadocTag?,
context: CommentResolutionContext
) =
when (tag.name) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down
Loading

0 comments on commit c01e49e

Please sign in to comment.