Support propagating inherited extensions from libraries
diff --git a/core/src/main/kotlin/DokkaBootstrapImpl.kt b/core/src/main/kotlin/DokkaBootstrapImpl.kt
index 126a017..4b75f31 100644
--- a/core/src/main/kotlin/DokkaBootstrapImpl.kt
+++ b/core/src/main/kotlin/DokkaBootstrapImpl.kt
@@ -69,7 +69,8 @@
languageVersion,
apiVersion,
cacheRoot,
- suppressedFiles.map { File(it) }
+ suppressedFiles.map { File(it) },
+ collectInheritedExtensionsFromLibraries
)
)
}
diff --git a/core/src/main/kotlin/Formats/JavaLayoutHtml/JavaLayoutHtmlFormat.kt b/core/src/main/kotlin/Formats/JavaLayoutHtml/JavaLayoutHtmlFormat.kt
index 5148097..dac5b5c 100644
--- a/core/src/main/kotlin/Formats/JavaLayoutHtml/JavaLayoutHtmlFormat.kt
+++ b/core/src/main/kotlin/Formats/JavaLayoutHtml/JavaLayoutHtmlFormat.kt
@@ -52,6 +52,10 @@
fun mainUri(node: DocumentationNode): URI = tryGetMainUri(node) ?: error("Unsupported ${node.kind}")
fun linkTo(to: DocumentationNode, from: URI): String {
+ to.links(NodeKind.ExternalLink).firstOrNull()?.let {
+ return it.name
+ }
+
return mainUri(to).relativeTo(from).toString()
}
diff --git a/core/src/main/kotlin/Generation/DokkaGenerator.kt b/core/src/main/kotlin/Generation/DokkaGenerator.kt
index 09e5ced..33170f3 100644
--- a/core/src/main/kotlin/Generation/DokkaGenerator.kt
+++ b/core/src/main/kotlin/Generation/DokkaGenerator.kt
@@ -160,6 +160,8 @@
with(injector.getInstance(DocumentationBuilder::class.java)) {
documentationModule.appendFragments(fragments, packageDocs.packageContent,
injector.getInstance(PackageDocumentationBuilder::class.java))
+
+ propagateExtensionFunctionsToSubclasses(fragments, resolutionFacade)
}
val javaFiles = coreEnvironment.getJavaSourceFiles().filter(filesToDocumentFilter)
diff --git a/core/src/main/kotlin/Generation/configurationImpl.kt b/core/src/main/kotlin/Generation/configurationImpl.kt
index 34d4154..52e8446 100644
--- a/core/src/main/kotlin/Generation/configurationImpl.kt
+++ b/core/src/main/kotlin/Generation/configurationImpl.kt
@@ -36,27 +36,28 @@
override val suppress: Boolean = false) : DokkaConfiguration.PackageOptions
data class DokkaConfigurationImpl(
- override val moduleName: String,
- override val classpath: List<String>,
- override val sourceRoots: List<SourceRootImpl>,
- override val samples: List<String>,
- override val includes: List<String>,
- override val outputDir: String,
- override val format: String,
- override val includeNonPublic: Boolean,
- override val includeRootPackage: Boolean,
- override val reportUndocumented: Boolean,
- override val skipEmptyPackages: Boolean,
- override val skipDeprecated: Boolean,
- override val jdkVersion: Int,
- override val generateIndexPages: Boolean,
- override val sourceLinks: List<SourceLinkDefinitionImpl>,
- override val impliedPlatforms: List<String>,
- override val perPackageOptions: List<PackageOptionsImpl>,
- override val externalDocumentationLinks: List<ExternalDocumentationLinkImpl>,
- override val noStdlibLink: Boolean,
- override val cacheRoot: String?,
- override val suppressedFiles: List<String>,
- override val languageVersion: String?,
- override val apiVersion: String?
+ override val moduleName: String,
+ override val classpath: List<String>,
+ override val sourceRoots: List<SourceRootImpl>,
+ override val samples: List<String>,
+ override val includes: List<String>,
+ override val outputDir: String,
+ override val format: String,
+ override val includeNonPublic: Boolean,
+ override val includeRootPackage: Boolean,
+ override val reportUndocumented: Boolean,
+ override val skipEmptyPackages: Boolean,
+ override val skipDeprecated: Boolean,
+ override val jdkVersion: Int,
+ override val generateIndexPages: Boolean,
+ override val sourceLinks: List<SourceLinkDefinitionImpl>,
+ override val impliedPlatforms: List<String>,
+ override val perPackageOptions: List<PackageOptionsImpl>,
+ override val externalDocumentationLinks: List<ExternalDocumentationLinkImpl>,
+ override val noStdlibLink: Boolean,
+ override val cacheRoot: String?,
+ override val suppressedFiles: List<String>,
+ override val languageVersion: String?,
+ override val apiVersion: String?,
+ override val collectInheritedExtensionsFromLibraries: Boolean
) : DokkaConfiguration
\ No newline at end of file
diff --git a/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt b/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt
index 0024862..aaaf6b9 100644
--- a/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt
+++ b/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt
@@ -11,6 +11,9 @@
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.descriptors.impl.EnumEntrySyntheticClassDescriptor
import org.jetbrains.kotlin.idea.kdoc.findKDoc
+import org.jetbrains.kotlin.idea.util.fuzzyExtensionReceiverType
+import org.jetbrains.kotlin.idea.util.makeNotNullable
+import org.jetbrains.kotlin.idea.util.toFuzzyType
import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
import org.jetbrains.kotlin.kdoc.psi.impl.KDocSection
import org.jetbrains.kotlin.lexer.KtTokens
@@ -23,10 +26,11 @@
import org.jetbrains.kotlin.resolve.descriptorUtil.*
import org.jetbrains.kotlin.resolve.findTopMostOverriddenDescriptors
import org.jetbrains.kotlin.resolve.jvm.JavaDescriptorResolver
+import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
+import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered
import org.jetbrains.kotlin.resolve.source.PsiSourceElement
import org.jetbrains.kotlin.resolve.source.getPsi
import org.jetbrains.kotlin.types.*
-import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
import org.jetbrains.kotlin.types.typeUtil.supertypes
import java.io.File
import java.nio.file.Path
@@ -51,7 +55,8 @@
val languageVersion: String?,
val apiVersion: String?,
cacheRoot: String? = null,
- val suppressedFiles: List<File> = emptyList()) {
+ val suppressedFiles: List<File> = emptyList(),
+ val collectInheritedExtensionsFromLibraries: Boolean = false) {
init {
if (perPackageOptions.any { it.prefix == "" })
throw IllegalArgumentException("Please do not register packageOptions with all match pattern, use global settings instead")
@@ -136,8 +141,20 @@
refGraph.register(descriptor.signature(), node)
}
- fun <T> nodeForDescriptor(descriptor: T, kind: NodeKind): DocumentationNode where T : DeclarationDescriptor, T : Named {
- val (doc, callback) = descriptorDocumentationParser.parseDocumentationAndDetails(descriptor, kind == NodeKind.Parameter)
+ fun <T> nodeForDescriptor(
+ descriptor: T,
+ kind: NodeKind,
+ external: Boolean = false
+ ): DocumentationNode where T : DeclarationDescriptor, T : Named {
+ val (doc, callback) =
+ if (external) {
+ Content.Empty to { node -> }
+ } else {
+ descriptorDocumentationParser.parseDocumentationAndDetails(
+ descriptor,
+ kind == NodeKind.Parameter
+ )
+ }
val node = DocumentationNode(descriptor.name.asString(), doc, kind).withModifiers(descriptor)
node.appendSignature(descriptor)
callback(node)
@@ -224,14 +241,20 @@
node.appendTextNode("?", NodeKind.NullabilityModifier)
}
if (classifierDescriptor != null) {
- val externalLink = linkResolver.externalDocumentationLinkResolver.buildExternalDocumentationLink(classifierDescriptor)
+ val externalLink =
+ linkResolver.externalDocumentationLinkResolver.buildExternalDocumentationLink(classifierDescriptor)
if (externalLink != null) {
- val targetNode = refGraph.lookup(classifierDescriptor.signature()) ?: classifierDescriptor.build(true)
- node.append(DocumentationNode(externalLink, Content.Empty, NodeKind.ExternalLink), RefKind.Link)
- node.append(targetNode, RefKind.ExternalType)
+ if (classifierDescriptor !is TypeParameterDescriptor) {
+ val targetNode =
+ refGraph.lookup(classifierDescriptor.signature()) ?: classifierDescriptor.build(true)
+ node.append(targetNode, RefKind.ExternalType)
+ node.append(DocumentationNode(externalLink, Content.Empty, NodeKind.ExternalLink), RefKind.Link)
+ }
} else {
- link(node, classifierDescriptor,
- if (classifierDescriptor.isBoringBuiltinClass()) RefKind.HiddenLink else RefKind.Link)
+ link(
+ node, classifierDescriptor,
+ if (classifierDescriptor.isBoringBuiltinClass()) RefKind.HiddenLink else RefKind.Link
+ )
}
if (classifierDescriptor !is TypeParameterDescriptor) {
node.append(
@@ -278,6 +301,17 @@
}
}
+ fun DocumentationNode.appendExternalLink(externalLink: String) {
+ append(DocumentationNode(externalLink, Content.Empty, NodeKind.ExternalLink), RefKind.Link)
+ }
+
+ fun DocumentationNode.appendExternalLink(descriptor: DeclarationDescriptor) {
+ val target = linkResolver.externalDocumentationLinkResolver.buildExternalDocumentationLink(descriptor)
+ if (target != null) {
+ appendExternalLink(target)
+ }
+ }
+
fun DocumentationNode.appendSinceKotlin(annotation: DocumentationNode) {
val kotlinVersion = annotation
.detail(NodeKind.Parameter)
@@ -424,15 +458,44 @@
declarations, allFqNames)
}
- propagateExtensionFunctionsToSubclasses(fragments)
}
- private fun propagateExtensionFunctionsToSubclasses(fragments: Collection<PackageFragmentDescriptor>) {
- val allDescriptors = fragments.flatMap { it.getMemberScope().getContributedDescriptors() }
- val allClasses = allDescriptors.filterIsInstance<ClassDescriptor>()
- val classHierarchy = buildClassHierarchy(allClasses)
+ fun propagateExtensionFunctionsToSubclasses(
+ fragments: Collection<PackageFragmentDescriptor>,
+ resolutionFacade: DokkaResolutionFacade
+ ) {
- val allExtensionFunctions = allDescriptors
+ val moduleDescriptor = resolutionFacade.moduleDescriptor
+
+ // Wide-collect all view descriptors
+ val allPackageViewDescriptors = generateSequence(listOf(moduleDescriptor.getPackage(FqName.ROOT))) { packages ->
+ packages
+ .flatMap { pkg ->
+ moduleDescriptor.getSubPackagesOf(pkg.fqName) { true }
+ }.map { fqName ->
+ moduleDescriptor.getPackage(fqName)
+ }.takeUnless { it.isEmpty() }
+ }.flatten()
+
+ val allDescriptors =
+ if (options.collectInheritedExtensionsFromLibraries) {
+ allPackageViewDescriptors.map { it.memberScope }
+ } else {
+ fragments.asSequence().map { it.getMemberScope() }
+ }.flatMap {
+ it.getDescriptorsFiltered(
+ DescriptorKindFilter.CALLABLES
+ ).asSequence()
+ }
+
+
+ val documentingDescriptors = fragments.flatMap { it.getMemberScope().getContributedDescriptors() }
+ val documentingClasses = documentingDescriptors.filterIsInstance<ClassDescriptor>()
+
+ val classHierarchy = buildClassHierarchy(documentingClasses)
+
+ val allExtensionFunctions =
+ allDescriptors
.filterIsInstance<CallableMemberDescriptor>()
.filter { it.extensionReceiverParameter != null }
val extensionFunctionsByName = allExtensionFunctions.groupBy { it.name }
@@ -440,15 +503,31 @@
for (extensionFunction in allExtensionFunctions) {
if (extensionFunction.dispatchReceiverParameter != null) continue
val possiblyShadowingFunctions = extensionFunctionsByName[extensionFunction.name]
- ?.filter { fn -> fn.canShadow(extensionFunction) }
+ ?.filter { fn -> fn.canShadow(extensionFunction) }
?: emptyList()
if (extensionFunction.extensionReceiverParameter?.type?.isDynamic() == true) continue
- val classDescriptor = extensionFunction.getExtensionClassDescriptor() ?: continue
- val subclasses = classHierarchy[classDescriptor] ?: continue
- subclasses.forEach { subclass ->
+ val subclasses =
+ classHierarchy.filter { (key) -> key.isExtensionApplicable(extensionFunction) }
+ if (subclasses.isEmpty()) continue
+ subclasses.values.flatten().forEach { subclass ->
if (subclass.isExtensionApplicable(extensionFunction) &&
- possiblyShadowingFunctions.none { subclass.isExtensionApplicable(it) }) {
+ possiblyShadowingFunctions.none { subclass.isExtensionApplicable(it) }) {
+
+ val hasExternalLink =
+ linkResolver.externalDocumentationLinkResolver.buildExternalDocumentationLink(
+ extensionFunction
+ ) != null
+ if (hasExternalLink) {
+ val containerDesc =
+ extensionFunction.containingDeclaration as? PackageFragmentDescriptor
+ if (containerDesc != null) {
+ val container = refGraph.lookup(containerDesc.signature())
+ ?: containerDesc.buildExternal()
+ container.append(extensionFunction.buildExternal(), RefKind.Member)
+ }
+ }
+
refGraph.link(subclass.signature(), extensionFunction.signature(), RefKind.Extension)
}
}
@@ -456,12 +535,9 @@
}
private fun ClassDescriptor.isExtensionApplicable(extensionFunction: CallableMemberDescriptor): Boolean {
- val receiverType = extensionFunction.extensionReceiverParameter!!.type
- if (receiverType.arguments.any { it.type.constructor.declarationDescriptor is TypeParameterDescriptor }) {
- val receiverClass = receiverType.constructor.declarationDescriptor
- return receiverClass is ClassDescriptor && DescriptorUtils.isSubclass(this, receiverClass)
- }
- return defaultType.isSubtypeOf(receiverType)
+ val receiverType = extensionFunction.fuzzyExtensionReceiverType()?.makeNotNullable()
+ val classType = defaultType.toFuzzyType(declaredTypeParameters)
+ return receiverType != null && classType.checkIsSubtypeOf(receiverType) != null
}
private fun buildClassHierarchy(classes: List<ClassDescriptor>): Map<ClassDescriptor, List<ClassDescriptor>> {
@@ -509,6 +585,24 @@
else -> throw IllegalStateException("Descriptor $this is not known")
}
+ fun PackageFragmentDescriptor.buildExternal(): DocumentationNode {
+ val node = DocumentationNode(fqName.asString(), Content.Empty, NodeKind.Package)
+
+ val externalLink = linkResolver.externalDocumentationLinkResolver.buildExternalDocumentationLink(this)
+ if (externalLink != null) {
+ node.append(DocumentationNode(externalLink, Content.Empty, NodeKind.ExternalLink), RefKind.Link)
+ }
+ register(this, node)
+ return node
+ }
+
+ fun CallableDescriptor.buildExternal(): DocumentationNode = when(this) {
+ is FunctionDescriptor -> build(true)
+ is PropertyDescriptor -> build(true)
+ else -> throw IllegalStateException("Descriptor $this is not known")
+ }
+
+
fun ClassifierDescriptor.build(external: Boolean = false): DocumentationNode = when (this) {
is ClassDescriptor -> build(external)
is TypeAliasDescriptor -> build(external)
@@ -545,7 +639,7 @@
isSubclassOfThrowable() -> NodeKind.Exception
else -> NodeKind.Class
}
- val node = nodeForDescriptor(this, kind)
+ val node = nodeForDescriptor(this, kind, external)
register(this, node)
typeConstructor.supertypes.forEach {
node.appendSupertype(this, it)
@@ -630,12 +724,12 @@
return (receiver?.type?.constructor?.declarationDescriptor as? ClassDescriptor)?.isCompanionObject ?: false
}
- fun FunctionDescriptor.build(): DocumentationNode {
+ fun FunctionDescriptor.build(external: Boolean = false): DocumentationNode {
if (ErrorUtils.containsErrorType(this)) {
logger.warn("Found an unresolved type in ${signatureWithSourceLocation()}")
}
- val node = nodeForDescriptor(this, if (inCompanionObject()) NodeKind.CompanionObjectFunction else NodeKind.Function)
+ val node = nodeForDescriptor(this, if (inCompanionObject()) NodeKind.CompanionObjectFunction else NodeKind.Function, external)
node.appendInPageChildren(typeParameters, RefKind.Detail)
extensionReceiverParameter?.let { node.appendChild(it, RefKind.Detail) }
@@ -643,8 +737,12 @@
node.appendType(returnType)
node.appendAnnotations(this)
node.appendModifiers(this)
- node.appendSourceLink(source)
- node.appendDefaultPlatforms(this)
+ if (!external) {
+ node.appendSourceLink(source)
+ node.appendDefaultPlatforms(this)
+ } else {
+ node.appendExternalLink(this)
+ }
overriddenDescriptors.forEach {
addOverrideLink(it, this)
@@ -665,32 +763,42 @@
}
}
- fun PropertyDescriptor.build(): DocumentationNode {
- val node = nodeForDescriptor(this, if (inCompanionObject()) NodeKind.CompanionObjectProperty else NodeKind.Property)
+ fun PropertyDescriptor.build(external: Boolean = false): DocumentationNode {
+ val node = nodeForDescriptor(
+ this,
+ if (inCompanionObject()) NodeKind.CompanionObjectProperty else NodeKind.Property,
+ external
+ )
node.appendInPageChildren(typeParameters, RefKind.Detail)
extensionReceiverParameter?.let { node.appendChild(it, RefKind.Detail) }
node.appendType(returnType)
node.appendAnnotations(this)
node.appendModifiers(this)
- node.appendSourceLink(source)
- if (isVar) {
- node.appendTextNode("var", NodeKind.Modifier)
- }
- getter?.let {
- if (!it.isDefault) {
- node.addAccessorDocumentation(descriptorDocumentationParser.parseDocumentation(it), "Getter")
+ if (!external) {
+ node.appendSourceLink(source)
+ if (isVar) {
+ node.appendTextNode("var", NodeKind.Modifier)
}
- }
- setter?.let {
- if (!it.isDefault) {
- node.addAccessorDocumentation(descriptorDocumentationParser.parseDocumentation(it), "Setter")
+
+ getter?.let {
+ if (!it.isDefault) {
+ node.addAccessorDocumentation(descriptorDocumentationParser.parseDocumentation(it), "Getter")
+ }
}
+ setter?.let {
+ if (!it.isDefault) {
+ node.addAccessorDocumentation(descriptorDocumentationParser.parseDocumentation(it), "Setter")
+ }
+ }
+ node.appendDefaultPlatforms(this)
+ }
+ if (external) {
+ node.appendExternalLink(this)
}
overriddenDescriptors.forEach {
addOverrideLink(it, this)
}
- node.appendDefaultPlatforms(this)
register(this, node)
return node
diff --git a/core/src/main/kotlin/Kotlin/ExternalDocumentationLinkResolver.kt b/core/src/main/kotlin/Kotlin/ExternalDocumentationLinkResolver.kt
index 108cee7..330e76a 100644
--- a/core/src/main/kotlin/Kotlin/ExternalDocumentationLinkResolver.kt
+++ b/core/src/main/kotlin/Kotlin/ExternalDocumentationLinkResolver.kt
@@ -154,8 +154,8 @@
fun buildExternalDocumentationLink(symbol: DeclarationDescriptor): String? {
val packageFqName: FqName =
when (symbol) {
- is DeclarationDescriptorNonRoot -> symbol.parents.firstOrNull { it is PackageFragmentDescriptor }?.fqNameSafe ?: return null
is PackageFragmentDescriptor -> symbol.fqName
+ is DeclarationDescriptorNonRoot -> symbol.parents.firstOrNull { it is PackageFragmentDescriptor }?.fqNameSafe ?: return null
else -> return null
}
diff --git a/core/src/main/kotlin/Model/DocumentationNode.kt b/core/src/main/kotlin/Model/DocumentationNode.kt
index a792460..85ecdf8 100644
--- a/core/src/main/kotlin/Model/DocumentationNode.kt
+++ b/core/src/main/kotlin/Model/DocumentationNode.kt
@@ -209,6 +209,8 @@
fun DocumentationNode.qualifiedName(): String {
if (kind == NodeKind.Type) {
return qualifiedNameFromType()
+ } else if (kind == NodeKind.Package) {
+ return name
}
return path.drop(1).map { it.name }.filter { it.length > 0 }.joinToString(".")
}
diff --git a/core/src/test/kotlin/TestAPI.kt b/core/src/test/kotlin/TestAPI.kt
index 559b715..aeff928 100644
--- a/core/src/test/kotlin/TestAPI.kt
+++ b/core/src/test/kotlin/TestAPI.kt
@@ -25,22 +25,24 @@
includeNonPublic: Boolean = true,
perPackageOptions: List<DokkaConfiguration.PackageOptions> = emptyList(),
noStdlibLink: Boolean = true,
+ collectInheritedExtensionsFromLibraries: Boolean = false,
verifier: (DocumentationModule) -> Unit) {
val documentation = DocumentationModule("test")
val options = DocumentationOptions(
- "",
- format,
- includeNonPublic = includeNonPublic,
- skipEmptyPackages = false,
- includeRootPackage = true,
- sourceLinks = listOf(),
- perPackageOptions = perPackageOptions,
- generateIndexPages = false,
- noStdlibLink = noStdlibLink,
- cacheRoot = "default",
- languageVersion = null,
- apiVersion = null
+ "",
+ format,
+ includeNonPublic = includeNonPublic,
+ skipEmptyPackages = false,
+ includeRootPackage = true,
+ sourceLinks = listOf(),
+ perPackageOptions = perPackageOptions,
+ generateIndexPages = false,
+ noStdlibLink = noStdlibLink,
+ cacheRoot = "default",
+ languageVersion = null,
+ apiVersion = null,
+ collectInheritedExtensionsFromLibraries = collectInheritedExtensionsFromLibraries
)
appendDocumentation(documentation, *roots,
@@ -162,6 +164,7 @@
format: String = "html",
includeNonPublic: Boolean = true,
noStdlibLink: Boolean = true,
+ collectInheritedExtensionsFromLibraries: Boolean = false,
outputGenerator: (DocumentationModule, StringBuilder) -> Unit) {
verifyModel(
*roots,
@@ -169,7 +172,8 @@
withKotlinRuntime = withKotlinRuntime,
format = format,
includeNonPublic = includeNonPublic,
- noStdlibLink = noStdlibLink
+ noStdlibLink = noStdlibLink,
+ collectInheritedExtensionsFromLibraries = collectInheritedExtensionsFromLibraries
) {
verifyModelOutput(it, outputExtension, roots.first().path, outputGenerator)
}
@@ -194,6 +198,7 @@
format: String = "html",
includeNonPublic: Boolean = true,
noStdlibLink: Boolean = true,
+ collectInheritedExtensionsFromLibraries: Boolean = false,
outputGenerator: (DocumentationModule, StringBuilder) -> Unit
) {
verifyOutput(
@@ -204,6 +209,7 @@
format,
includeNonPublic,
noStdlibLink,
+ collectInheritedExtensionsFromLibraries,
outputGenerator
)
}
diff --git a/core/src/test/kotlin/format/JavaLayoutHtmlFormatTest.kt b/core/src/test/kotlin/format/JavaLayoutHtmlFormatTest.kt
index f93139e..5da49d3 100644
--- a/core/src/test/kotlin/format/JavaLayoutHtmlFormatTest.kt
+++ b/core/src/test/kotlin/format/JavaLayoutHtmlFormatTest.kt
@@ -16,33 +16,5 @@
verifyPackageNode("topLevel.kt")
}
- private fun verifyNode(fileName: String) {
- verifyOutput(
- "testdata/format/java-layout-html/$fileName",
- ".html",
- format = "java-layout-html",
- withKotlinRuntime = true,
- noStdlibLink = false
- ) { model, output ->
- buildPagesAndReadInto(
- model,
- listOf(model.members.single().members.single()),
- output
- )
- }
- }
- private fun verifyPackageNode(fileName: String) {
- verifyOutput(
- "testdata/format/java-layout-html/$fileName",
- ".package-summary.html",
- format = "java-layout-html"
- ) { model, output ->
- buildPagesAndReadInto(
- model,
- listOf(model.members.single()),
- output
- )
- }
- }
}
\ No newline at end of file
diff --git a/core/src/test/kotlin/format/JavaLayoutHtmlFormatTestCase.kt b/core/src/test/kotlin/format/JavaLayoutHtmlFormatTestCase.kt
index 928a7d2..0b8fca2 100644
--- a/core/src/test/kotlin/format/JavaLayoutHtmlFormatTestCase.kt
+++ b/core/src/test/kotlin/format/JavaLayoutHtmlFormatTestCase.kt
@@ -30,7 +30,8 @@
apiVersion = null,
languageVersion = null,
generateIndexPages = false,
- noStdlibLink = false
+ noStdlibLink = false,
+ collectInheritedExtensionsFromLibraries = true
)
val injector: Injector by lazy {
@@ -58,7 +59,7 @@
}
- fun buildPagesAndReadInto(model: DocumentationNode, nodes: List<DocumentationNode>, sb: StringBuilder) =
+ protected fun buildPagesAndReadInto(model: DocumentationNode, nodes: List<DocumentationNode>, sb: StringBuilder) =
with(injector.getInstance(Generator::class.java)) {
this as JavaLayoutHtmlFormatGenerator
buildPages(listOf(model))
@@ -69,4 +70,34 @@
}
}
+ protected fun verifyNode(fileName: String) {
+ verifyOutput(
+ "testdata/format/java-layout-html/$fileName",
+ ".html",
+ format = "java-layout-html",
+ withKotlinRuntime = true,
+ noStdlibLink = false,
+ collectInheritedExtensionsFromLibraries = true
+ ) { model, output ->
+ buildPagesAndReadInto(
+ model,
+ listOf(model.members.single().members.single()),
+ output
+ )
+ }
+ }
+
+ protected fun verifyPackageNode(fileName: String) {
+ verifyOutput(
+ "testdata/format/java-layout-html/$fileName",
+ ".package-summary.html",
+ format = "java-layout-html"
+ ) { model, output ->
+ buildPagesAndReadInto(
+ model,
+ listOf(model.members.single()),
+ output
+ )
+ }
+ }
}
\ No newline at end of file
diff --git a/integration/src/main/kotlin/org/jetbrains/dokka/configuration.kt b/integration/src/main/kotlin/org/jetbrains/dokka/configuration.kt
index 90e5b5f..46a5727 100644
--- a/integration/src/main/kotlin/org/jetbrains/dokka/configuration.kt
+++ b/integration/src/main/kotlin/org/jetbrains/dokka/configuration.kt
@@ -41,6 +41,7 @@
val noStdlibLink: Boolean
val cacheRoot: String?
val suppressedFiles: List<String>
+ val collectInheritedExtensionsFromLibraries: Boolean
interface SourceRoot {
val path: String
@@ -82,29 +83,30 @@
}
data class SerializeOnlyDokkaConfiguration(
- override val moduleName: String,
- override val classpath: List<String>,
- override val sourceRoots: List<DokkaConfiguration.SourceRoot>,
- override val samples: List<String>,
- override val includes: List<String>,
- override val outputDir: String,
- override val format: String,
- override val includeNonPublic: Boolean,
- override val includeRootPackage: Boolean,
- override val reportUndocumented: Boolean,
- override val skipEmptyPackages: Boolean,
- override val skipDeprecated: Boolean,
- override val jdkVersion: Int,
- override val generateIndexPages: Boolean,
- override val sourceLinks: List<DokkaConfiguration.SourceLinkDefinition>,
- override val impliedPlatforms: List<String>,
- override val perPackageOptions: List<DokkaConfiguration.PackageOptions>,
- override val externalDocumentationLinks: List<DokkaConfiguration.ExternalDocumentationLink>,
- override val noStdlibLink: Boolean,
- override val cacheRoot: String?,
- override val suppressedFiles: List<String>,
- override val languageVersion: String?,
- override val apiVersion: String?
+ override val moduleName: String,
+ override val classpath: List<String>,
+ override val sourceRoots: List<DokkaConfiguration.SourceRoot>,
+ override val samples: List<String>,
+ override val includes: List<String>,
+ override val outputDir: String,
+ override val format: String,
+ override val includeNonPublic: Boolean,
+ override val includeRootPackage: Boolean,
+ override val reportUndocumented: Boolean,
+ override val skipEmptyPackages: Boolean,
+ override val skipDeprecated: Boolean,
+ override val jdkVersion: Int,
+ override val generateIndexPages: Boolean,
+ override val sourceLinks: List<DokkaConfiguration.SourceLinkDefinition>,
+ override val impliedPlatforms: List<String>,
+ override val perPackageOptions: List<DokkaConfiguration.PackageOptions>,
+ override val externalDocumentationLinks: List<DokkaConfiguration.ExternalDocumentationLink>,
+ override val noStdlibLink: Boolean,
+ override val cacheRoot: String?,
+ override val suppressedFiles: List<String>,
+ override val languageVersion: String?,
+ override val apiVersion: String?,
+ override val collectInheritedExtensionsFromLibraries: Boolean
) : DokkaConfiguration
diff --git a/runners/cli/src/main/kotlin/cli/main.kt b/runners/cli/src/main/kotlin/cli/main.kt
index fe945ed..111e142 100644
--- a/runners/cli/src/main/kotlin/cli/main.kt
+++ b/runners/cli/src/main/kotlin/cli/main.kt
@@ -62,6 +62,9 @@
@set:Argument(value = "apiVersion", description = "Kotlin Api Version to pass to Kotlin Analysis")
var apiVersion: String? = null
+ @set:Argument(value = "collectInheritedExtensionsFromLibraries", description = "Search for applicable extensions in libraries")
+ var collectInheritedExtensionsFromLibraries: Boolean = false
+
}
@@ -106,18 +109,19 @@
val classPath = arguments.classpath.split(File.pathSeparatorChar).toList()
val documentationOptions = DocumentationOptions(
- arguments.outputDir.let { if (it.endsWith('/')) it else it + '/' },
- arguments.outputFormat,
- skipDeprecated = arguments.nodeprecated,
- sourceLinks = sourceLinks,
- impliedPlatforms = arguments.impliedPlatforms.split(','),
- perPackageOptions = parsePerPackageOptions(arguments.packageOptions),
- jdkVersion = arguments.jdkVersion,
- externalDocumentationLinks = parseLinks(arguments.links),
- noStdlibLink = arguments.noStdlibLink,
- cacheRoot = arguments.cacheRoot,
- languageVersion = arguments.languageVersion,
- apiVersion = arguments.apiVersion
+ arguments.outputDir.let { if (it.endsWith('/')) it else it + '/' },
+ arguments.outputFormat,
+ skipDeprecated = arguments.nodeprecated,
+ sourceLinks = sourceLinks,
+ impliedPlatforms = arguments.impliedPlatforms.split(','),
+ perPackageOptions = parsePerPackageOptions(arguments.packageOptions),
+ jdkVersion = arguments.jdkVersion,
+ externalDocumentationLinks = parseLinks(arguments.links),
+ noStdlibLink = arguments.noStdlibLink,
+ cacheRoot = arguments.cacheRoot,
+ languageVersion = arguments.languageVersion,
+ apiVersion = arguments.apiVersion,
+ collectInheritedExtensionsFromLibraries = arguments.collectInheritedExtensionsFromLibraries
)
val generator = DokkaGenerator(
diff --git a/runners/gradle-plugin/src/main/kotlin/main.kt b/runners/gradle-plugin/src/main/kotlin/main.kt
index bdecc3f..5138fce 100644
--- a/runners/gradle-plugin/src/main/kotlin/main.kt
+++ b/runners/gradle-plugin/src/main/kotlin/main.kt
@@ -122,6 +122,9 @@
@Optional @Input
var apiVersion: String? = null
+ @Input
+ var collectInheritedExtensionsFromLibraries: Boolean = false
+
@get:Input
internal val kotlinCompileBasedClasspathAndSourceRoots: ClasspathAndSourceRoots by lazy { extractClasspathAndSourceRootsFromKotlinTasks() }
@@ -269,29 +272,31 @@
val bootstrapProxy: DokkaBootstrap = automagicTypedProxy(javaClass.classLoader, bootstrapInstance)
val configuration = SerializeOnlyDokkaConfiguration(
- moduleName,
- fullClasspath.map { it.absolutePath },
- sourceRoots,
- samples.filterNotNull().map { project.file(it).absolutePath },
- includes.filterNotNull().map { project.file(it).absolutePath },
- outputDirectory,
- outputFormat,
- includeNonPublic,
- false,
- reportNotDocumented,
- skipEmptyPackages,
- skipDeprecated,
- jdkVersion,
- true,
- linkMappings,
- impliedPlatforms,
- perPackageOptions,
- externalDocumentationLinks,
- noStdlibLink,
- cacheRoot,
- collectSuppressedFiles(sourceRoots),
- languageVersion,
- apiVersion)
+ moduleName,
+ fullClasspath.map { it.absolutePath },
+ sourceRoots,
+ samples.filterNotNull().map { project.file(it).absolutePath },
+ includes.filterNotNull().map { project.file(it).absolutePath },
+ outputDirectory,
+ outputFormat,
+ includeNonPublic,
+ false,
+ reportNotDocumented,
+ skipEmptyPackages,
+ skipDeprecated,
+ jdkVersion,
+ true,
+ linkMappings,
+ impliedPlatforms,
+ perPackageOptions,
+ externalDocumentationLinks,
+ noStdlibLink,
+ cacheRoot,
+ collectSuppressedFiles(sourceRoots),
+ languageVersion,
+ apiVersion,
+ collectInheritedExtensionsFromLibraries
+ )
bootstrapProxy.configure(