diff options
author | Dmitry Jemerov <yole@jetbrains.com> | 2015-10-30 18:43:48 +0100 |
---|---|---|
committer | Dmitry Jemerov <yole@jetbrains.com> | 2015-10-30 18:43:48 +0100 |
commit | e4b2ae90bf0e84f76ceb7c56b7c128d28adad917 (patch) | |
tree | b1e7d86b808b41909679d44da8ac97bec1928c44 | |
parent | 17492c5f48c459dd44eafb0e747c1164193ca7f7 (diff) | |
download | dokka-e4b2ae90bf0e84f76ceb7c56b7c128d28adad917.tar.gz dokka-e4b2ae90bf0e84f76ceb7c56b7c128d28adad917.tar.bz2 dokka-e4b2ae90bf0e84f76ceb7c56b7c128d28adad917.zip |
initial support for generating javadoc from Kotlin light classes
-rw-r--r-- | javadoc/src/main/kotlin/docbase.kt | 15 | ||||
-rw-r--r-- | javadoc/src/main/kotlin/dokka-adapters.kt | 9 | ||||
-rw-r--r-- | src/Formats/FormatDescriptor.kt | 4 | ||||
-rw-r--r-- | src/Formats/StandardFormats.kt | 12 | ||||
-rw-r--r-- | src/Generation/FileGenerator.kt | 4 | ||||
-rw-r--r-- | src/Java/JavaDocumentationBuilder.kt | 10 | ||||
-rw-r--r-- | src/Kotlin/DocumentationBuilder.kt | 145 | ||||
-rw-r--r-- | src/Kotlin/KotlinAsJavaDocumentationBuilder.kt | 27 | ||||
-rw-r--r-- | src/Utilities/GuiceModule.kt | 7 | ||||
-rw-r--r-- | src/main.kt | 24 | ||||
-rw-r--r-- | test/src/TestAPI.kt | 12 | ||||
-rw-r--r-- | test/src/model/KotlinAsJavaTest.kt | 32 |
12 files changed, 221 insertions, 80 deletions
diff --git a/javadoc/src/main/kotlin/docbase.kt b/javadoc/src/main/kotlin/docbase.kt index 9cb0148d..06bbaa58 100644 --- a/javadoc/src/main/kotlin/docbase.kt +++ b/javadoc/src/main/kotlin/docbase.kt @@ -15,7 +15,7 @@ private interface HasDocumentationNode { } open class DocumentationNodeBareAdapter(override val node: DocumentationNode) : Doc, HasDocumentationNode { - private var rawCommentText_ = rawCommentText + private var rawCommentText_: String? = null override fun name(): String = node.name override fun position(): SourcePosition? = SourcePositionAdapter(node) @@ -31,7 +31,7 @@ open class DocumentationNodeBareAdapter(override val node: DocumentationNode) : rawCommentText_ = rawDocumentation ?: "" } - override fun getRawCommentText(): String = rawCommentText_ + override fun getRawCommentText(): String = rawCommentText_ ?: "" override fun isError(): Boolean = false override fun isException(): Boolean = node.kind == DocumentationNode.Kind.Exception @@ -357,7 +357,14 @@ class FieldAdapter(module: ModuleNodeAdapter, node: DocumentationNode) : Documen override fun isVolatile(): Boolean = node.hasAnnotation(Volatile::class) } -open class ClassDocumentationNodeAdapter(module: ModuleNodeAdapter, val classNode: DocumentationNode) : DocumentationNodeAdapter(module, classNode), Type by TypeAdapter(module, classNode), ProgramElementDoc by ProgramElementAdapter(module, classNode), ClassDoc { +open class ClassDocumentationNodeAdapter(module: ModuleNodeAdapter, val classNode: DocumentationNode, val name: String = classNode.name) + : DocumentationNodeAdapter(module, classNode), + Type by TypeAdapter(module, classNode), + ProgramElementDoc by ProgramElementAdapter(module, classNode), + ClassDoc { + + override fun name(): String = name + override fun constructors(filter: Boolean): Array<out ConstructorDoc> = classNode.members(DocumentationNode.Kind.Constructor).map { ConstructorAdapter(module, it) }.toTypedArray() override fun constructors(): Array<out ConstructorDoc> = constructors(true) override fun importedPackages(): Array<out PackageDoc> = emptyArray() @@ -419,7 +426,7 @@ open class ClassDocumentationNodeAdapter(module: ModuleNodeAdapter, val classNod return false } - override fun innerClasses(): Array<out ClassDoc> = classNode.members(DocumentationNode.Kind.Class).map { ClassDocumentationNodeAdapter(module, it) }.toTypedArray() + override fun innerClasses(): Array<out ClassDoc> = classNode.members(DocumentationNode.Kind.Class).map { ClassDocumentationNodeAdapter(module, it, name + "." + it.name) }.toTypedArray() override fun innerClasses(filter: Boolean): Array<out ClassDoc> = innerClasses() } diff --git a/javadoc/src/main/kotlin/dokka-adapters.kt b/javadoc/src/main/kotlin/dokka-adapters.kt index 0f7c53d7..a863faf7 100644 --- a/javadoc/src/main/kotlin/dokka-adapters.kt +++ b/javadoc/src/main/kotlin/dokka-adapters.kt @@ -1,10 +1,11 @@ package org.jetbrains.dokka.javadoc +import com.google.inject.Inject import com.sun.tools.doclets.formats.html.HtmlDoclet import org.jetbrains.dokka.* import org.jetbrains.dokka.Formats.FormatDescriptor -class JavadocGenerator(val conf: DokkaGenerator) : Generator { +class JavadocGenerator @Inject constructor (val conf: DokkaGenerator) : Generator { override fun buildPages(nodes: Iterable<DocumentationNode>) { val module = nodes.single() as DocumentationModule @@ -24,6 +25,8 @@ class JavadocFormatDescriptor : FormatDescriptor { get() = null override val generatorServiceClass: Class<out Generator> - get() = javaClass<JavadocGenerator>() -} + get() = JavadocGenerator::class.java + override val packageDocumentationBuilderServiceClass: Class<out PackageDocumentationBuilder>? + get() = KotlinAsJavaDocumentationBuilder::class.java +} diff --git a/src/Formats/FormatDescriptor.kt b/src/Formats/FormatDescriptor.kt index beff730f..cc12dfb9 100644 --- a/src/Formats/FormatDescriptor.kt +++ b/src/Formats/FormatDescriptor.kt @@ -3,9 +3,11 @@ package org.jetbrains.dokka.Formats import org.jetbrains.dokka.FormatService import org.jetbrains.dokka.Generator import org.jetbrains.dokka.OutlineFormatService +import org.jetbrains.dokka.PackageDocumentationBuilder public interface FormatDescriptor { val formatServiceClass: Class<out FormatService>? val outlineServiceClass: Class<out OutlineFormatService>? val generatorServiceClass: Class<out Generator> -}
\ No newline at end of file + val packageDocumentationBuilderServiceClass: Class<out PackageDocumentationBuilder>? +} diff --git a/src/Formats/StandardFormats.kt b/src/Formats/StandardFormats.kt index 658735c0..12b5d85d 100644 --- a/src/Formats/StandardFormats.kt +++ b/src/Formats/StandardFormats.kt @@ -11,6 +11,9 @@ class HtmlFormatDescriptor : FormatDescriptor { override val generatorServiceClass: Class<out Generator> get() = FileGenerator::class.java + + override val packageDocumentationBuilderServiceClass: Class<out PackageDocumentationBuilder>? + get() = null } class KotlinWebsiteFormatDescriptor : FormatDescriptor { @@ -22,6 +25,9 @@ class KotlinWebsiteFormatDescriptor : FormatDescriptor { override val generatorServiceClass: Class<out Generator> get() = FileGenerator::class.java + + override val packageDocumentationBuilderServiceClass: Class<out PackageDocumentationBuilder>? + get() = null } class JekyllFormatDescriptor : FormatDescriptor { @@ -33,6 +39,9 @@ class JekyllFormatDescriptor : FormatDescriptor { override val generatorServiceClass: Class<out Generator> get() = FileGenerator::class.java + + override val packageDocumentationBuilderServiceClass: Class<out PackageDocumentationBuilder>? + get() = null } class MarkdownFormatDescriptor : FormatDescriptor { @@ -44,4 +53,7 @@ class MarkdownFormatDescriptor : FormatDescriptor { override val generatorServiceClass: Class<out Generator> get() = FileGenerator::class.java + + override val packageDocumentationBuilderServiceClass: Class<out PackageDocumentationBuilder>? + get() = null } diff --git a/src/Generation/FileGenerator.kt b/src/Generation/FileGenerator.kt index c4025088..810038fa 100644 --- a/src/Generation/FileGenerator.kt +++ b/src/Generation/FileGenerator.kt @@ -6,10 +6,10 @@ import java.io.FileOutputStream import java.io.IOException import java.io.OutputStreamWriter -public class FileGenerator @Inject constructor(val locationService: FileLocationService, - val formatService: FormatService) : Generator { +public class FileGenerator @Inject constructor(val locationService: FileLocationService) : Generator { @set:Inject(optional = true) var outlineService: OutlineFormatService? = null + @set:Inject(optional = true) lateinit var formatService: FormatService override fun buildPages(nodes: Iterable<DocumentationNode>) { val specificLocationService = locationService.withExtension(formatService.extension) diff --git a/src/Java/JavaDocumentationBuilder.kt b/src/Java/JavaDocumentationBuilder.kt index f3cedc07..660ac4a8 100644 --- a/src/Java/JavaDocumentationBuilder.kt +++ b/src/Java/JavaDocumentationBuilder.kt @@ -15,7 +15,11 @@ public class JavaDocumentationBuilder(private val options: DocumentationOptions, return } val packageNode = module.findOrCreatePackageNode(file.packageName, emptyMap()) - packageNode.appendChildren(file.classes) { build() } + appendClasses(packageNode, file.classes) + } + + fun appendClasses(packageNode: DocumentationNode, classes: Array<PsiClass>) { + packageNode.appendChildren(classes) { build() } } data class JavadocParseResult(val content: Content, val deprecatedContent: Content?) @@ -47,9 +51,9 @@ public class JavaDocumentationBuilder(private val options: DocumentationOptions, private fun PsiDocTag.contentElements(): Iterable<PsiElement> { val tagValueElements = children - .dropWhile { it.node.elementType == JavaDocTokenType.DOC_TAG_NAME } + .dropWhile { it.node?.elementType == JavaDocTokenType.DOC_TAG_NAME } .dropWhile { it is PsiWhiteSpace } - .filterNot { it.node.elementType == JavaDocTokenType.DOC_COMMENT_LEADING_ASTERISKS } + .filterNot { it.node?.elementType == JavaDocTokenType.DOC_COMMENT_LEADING_ASTERISKS } return if (getSubjectName() != null) tagValueElements.dropWhile { it is PsiDocTagValue } else tagValueElements } diff --git a/src/Kotlin/DocumentationBuilder.kt b/src/Kotlin/DocumentationBuilder.kt index 2d3105ac..375ca4bd 100644 --- a/src/Kotlin/DocumentationBuilder.kt +++ b/src/Kotlin/DocumentationBuilder.kt @@ -1,5 +1,6 @@ package org.jetbrains.dokka +import com.intellij.openapi.project.Project import com.intellij.openapi.util.text.StringUtil import com.intellij.psi.util.PsiTreeUtil import org.jetbrains.dokka.DocumentationNode.Kind @@ -43,6 +44,14 @@ private fun isSamePackage(descriptor1: DeclarationDescriptor, descriptor2: Decla return package1 != null && package2 != null && package1.fqName == package2.fqName } +interface PackageDocumentationBuilder { + fun buildPackageDocumentation(project: Project, + packageName: FqName, + packageNode: DocumentationNode, + declarations: List<DeclarationDescriptor>, + options: DocumentationOptions, refGraph: NodeReferenceGraph, logger: DokkaLogger) +} + class DocumentationBuilder(val resolutionFacade: ResolutionFacade, val session: ResolveSession, val options: DocumentationOptions, @@ -124,10 +133,6 @@ class DocumentationBuilder(val resolutionFacade: ResolutionFacade, return null } - fun DeclarationDescriptor.isDeprecated(): Boolean = annotations.any { - DescriptorUtils.getFqName(it.type.constructor.declarationDescriptor!!).asString() == "kotlin.Deprecated" - } || (this is ConstructorDescriptor && containingDeclaration.isDeprecated()) - fun DeclarationDescriptor.signature(): String = when(this) { is ClassDescriptor, is PackageFragmentDescriptor -> DescriptorUtils.getFqName(this).asString() is PropertyDescriptor -> containingDeclaration.signature() + "#" + name + receiverSignature() @@ -353,17 +358,6 @@ class DocumentationBuilder(val resolutionFacade: ResolutionFacade, } } - private fun AnnotationDescriptor.isDocumented(): Boolean { - if (source.getPsi() != null && mustBeDocumented()) return true - val annotationClassName = type.constructor.declarationDescriptor?.fqNameSafe?.asString() - return annotationClassName == "kotlin.Extension" - } - - fun AnnotationDescriptor.mustBeDocumented(): Boolean { - val annotationClass = type.constructor.declarationDescriptor as? Annotated ?: return false - return annotationClass.isDocumentedAnnotation() - } - fun DocumentationNode.appendModifiers(descriptor: DeclarationDescriptor) { val psi = (descriptor as DeclarationDescriptorWithSource).source.getPsi() as? KtModifierListOwner ?: return KtTokens.MODIFIER_KEYWORDS_ARRAY.filter { it !in knownModifiers }.forEach { @@ -400,12 +394,6 @@ class DocumentationBuilder(val resolutionFacade: ResolutionFacade, (!options.skipDeprecated || !isDeprecated()) } - fun DeclarationDescriptor.isDocumentationSuppressed(): Boolean { - val doc = KDocFinder.findKDoc(this) - return doc is KDocSection && doc.findTagByName("suppress") != null - } - - fun DocumentationNode.appendMembers(descriptors: Iterable<DeclarationDescriptor>) { descriptors.forEach { descriptor -> if (descriptor is CallableMemberDescriptor && descriptor.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) { @@ -427,40 +415,18 @@ class DocumentationBuilder(val resolutionFacade: ResolutionFacade, } } - fun DocumentationNode.getParentForPackageMember(descriptor: DeclarationDescriptor, - externalClassNodes: MutableMap<FqName, DocumentationNode>): DocumentationNode { - if (descriptor is CallableMemberDescriptor) { - val extensionClassDescriptor = descriptor.getExtensionClassDescriptor() - if (extensionClassDescriptor != null && !isSamePackage(descriptor, extensionClassDescriptor) && - !ErrorUtils.isError(extensionClassDescriptor)) { - val fqName = DescriptorUtils.getFqNameSafe(extensionClassDescriptor) - return externalClassNodes.getOrPut(fqName, { - val newNode = DocumentationNode(fqName.asString(), Content.Empty, Kind.ExternalClass) - append(newNode, DocumentationReference.Kind.Member) - newNode - }) - } - } - return this - } - fun DocumentationModule.appendFragments(fragments: Collection<PackageFragmentDescriptor>, - packageContent: Map<String, Content>) { - val descriptors = hashMapOf<String, List<DeclarationDescriptor>>() - for ((name, parts) in fragments.groupBy { it.fqName }) { - descriptors.put(name.asString(), parts.flatMap { it.getMemberScope().getAllDescriptors() }) - } - for ((packageName, declarations) in descriptors) { - if (options.skipEmptyPackages && declarations.none { it.isDocumented()}) continue + packageContent: Map<String, Content>, + packageDocumentationBuilder: PackageDocumentationBuilder = KotlinPackageDocumentationBuilder()) { + val allFqNames = fragments.map { it.fqName }.distinct() + + for (packageName in allFqNames) { + val declarations = fragments.filter { it.fqName == packageName }.flatMap { it.getMemberScope().getAllDescriptors() } + + if (options.skipEmptyPackages && declarations.none { it.isDocumented() }) continue logger.info(" package $packageName: ${declarations.count()} declarations") - val packageNode = findOrCreatePackageNode(packageName, packageContent) - val externalClassNodes = hashMapOf<FqName, DocumentationNode>() - declarations.forEach { descriptor -> - if (descriptor.isDocumented()) { - val parent = packageNode.getParentForPackageMember(descriptor, externalClassNodes) - parent.appendChild(descriptor, DocumentationReference.Kind.Member) - } - } + val packageNode = findOrCreatePackageNode(packageName.asString(), packageContent) + packageDocumentationBuilder.buildPackageDocumentation(resolutionFacade.project, packageName, packageNode, declarations, options, refGraph, logger) } } @@ -526,15 +492,6 @@ class DocumentationBuilder(val resolutionFacade: ResolutionFacade, return (receiver?.type?.constructor?.declarationDescriptor as? ClassDescriptor)?.isCompanionObject ?: false } - fun CallableMemberDescriptor.getExtensionClassDescriptor(): ClassifierDescriptor? { - val extensionReceiver = extensionReceiverParameter - if (extensionReceiver != null) { - val type = extensionReceiver.type - return type.constructor.declarationDescriptor as? ClassDescriptor - } - return null - } - fun FunctionDescriptor.build(): DocumentationNode { if (ErrorUtils.containsErrorType(this)) { logger.warn("Found an unresolved type in ${signatureWithSourceLocation()}") @@ -707,4 +664,68 @@ class DocumentationBuilder(val resolutionFacade: ResolutionFacade, DocumentationNode(valueString, Content.Empty, DocumentationNode.Kind.Value) } } + + inner class KotlinPackageDocumentationBuilder : PackageDocumentationBuilder { + override fun buildPackageDocumentation(project: Project, + packageName: FqName, + packageNode: DocumentationNode, + declarations: List<DeclarationDescriptor>, + options: DocumentationOptions, + refGraph: NodeReferenceGraph, logger: DokkaLogger) { + val externalClassNodes = hashMapOf<FqName, DocumentationNode>() + declarations.forEach { descriptor -> + if (descriptor.isDocumented()) { + val parent = packageNode.getParentForPackageMember(descriptor, externalClassNodes) + parent.appendChild(descriptor, DocumentationReference.Kind.Member) + } + } + } + } +} + +private fun AnnotationDescriptor.isDocumented(): Boolean { + if (source.getPsi() != null && mustBeDocumented()) return true + val annotationClassName = type.constructor.declarationDescriptor?.fqNameSafe?.asString() + return annotationClassName == "kotlin.Extension" +} + +fun AnnotationDescriptor.mustBeDocumented(): Boolean { + val annotationClass = type.constructor.declarationDescriptor as? Annotated ?: return false + return annotationClass.isDocumentedAnnotation() +} + +fun DeclarationDescriptor.isDocumentationSuppressed(): Boolean { + val doc = KDocFinder.findKDoc(this) + return doc is KDocSection && doc.findTagByName("suppress") != null +} + +fun DeclarationDescriptor.isDeprecated(): Boolean = annotations.any { + DescriptorUtils.getFqName(it.type.constructor.declarationDescriptor!!).asString() == "kotlin.Deprecated" +} || (this is ConstructorDescriptor && containingDeclaration.isDeprecated()) + +fun DocumentationNode.getParentForPackageMember(descriptor: DeclarationDescriptor, + externalClassNodes: MutableMap<FqName, DocumentationNode>): DocumentationNode { + if (descriptor is CallableMemberDescriptor) { + val extensionClassDescriptor = descriptor.getExtensionClassDescriptor() + if (extensionClassDescriptor != null && !isSamePackage(descriptor, extensionClassDescriptor) && + !ErrorUtils.isError(extensionClassDescriptor)) { + val fqName = DescriptorUtils.getFqNameSafe(extensionClassDescriptor) + return externalClassNodes.getOrPut(fqName, { + val newNode = DocumentationNode(fqName.asString(), Content.Empty, Kind.ExternalClass) + append(newNode, DocumentationReference.Kind.Member) + newNode + }) + } + } + return this } + +fun CallableMemberDescriptor.getExtensionClassDescriptor(): ClassifierDescriptor? { + val extensionReceiver = extensionReceiverParameter + if (extensionReceiver != null) { + val type = extensionReceiver.type + return type.constructor.declarationDescriptor as? ClassDescriptor + } + return null +} + diff --git a/src/Kotlin/KotlinAsJavaDocumentationBuilder.kt b/src/Kotlin/KotlinAsJavaDocumentationBuilder.kt new file mode 100644 index 00000000..ae295769 --- /dev/null +++ b/src/Kotlin/KotlinAsJavaDocumentationBuilder.kt @@ -0,0 +1,27 @@ +package org.jetbrains.dokka + +import com.intellij.openapi.project.Project +import com.intellij.psi.JavaPsiFacade +import org.jetbrains.kotlin.asJava.KotlinLightElement +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.name.FqName + +class KotlinAsJavaDocumentationBuilder() : PackageDocumentationBuilder { + override fun buildPackageDocumentation(project: Project, + packageName: FqName, + packageNode: DocumentationNode, + declarations: List<DeclarationDescriptor>, + options: DocumentationOptions, + refGraph: NodeReferenceGraph, + logger: DokkaLogger) { + val psiPackage = JavaPsiFacade.getInstance(project).findPackage(packageName.asString()) + if (psiPackage == null) { + logger.error("Cannot find Java package by qualified name: ${packageName.asString()}") + return + } + val javaDocumentationBuilder = JavaDocumentationBuilder(options, refGraph) + psiPackage.classes.filter { it is KotlinLightElement<*, *> }.forEach { + javaDocumentationBuilder.appendClasses(packageNode, arrayOf(it)) + } + } +} diff --git a/src/Utilities/GuiceModule.kt b/src/Utilities/GuiceModule.kt index 855d70b6..e852ae19 100644 --- a/src/Utilities/GuiceModule.kt +++ b/src/Utilities/GuiceModule.kt @@ -4,6 +4,7 @@ import com.google.inject.Binder import com.google.inject.Module import com.google.inject.Provider import com.google.inject.name.Names +import com.google.inject.util.Providers import org.jetbrains.dokka.* import org.jetbrains.dokka.Formats.FormatDescriptor import java.io.File @@ -40,6 +41,12 @@ class GuiceModule(val config: DokkaGenerator) : Module { descriptor.formatServiceClass?.let { clazz -> binder.bind(FormatService::class.java).to(clazz) } + if (descriptor.packageDocumentationBuilderServiceClass != null) { + binder.bind(PackageDocumentationBuilder::class.java).to(descriptor.packageDocumentationBuilderServiceClass) + } else { + binder.bind(PackageDocumentationBuilder::class.java).toProvider(Providers.of(null)) + } + binder.bind(Generator::class.java).to(descriptor.generatorServiceClass) } diff --git a/src/main.kt b/src/main.kt index 1d2442f2..d0e693e9 100644 --- a/src/main.kt +++ b/src/main.kt @@ -17,6 +17,8 @@ import org.jetbrains.kotlin.cli.common.messages.MessageRenderer import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment import org.jetbrains.kotlin.cli.jvm.config.JavaSourceRoot import org.jetbrains.kotlin.config.CommonConfigurationKeys +import org.jetbrains.kotlin.resolve.LazyTopDownAnalyzerForTopLevel +import org.jetbrains.kotlin.resolve.TopDownAnalysisMode import org.jetbrains.kotlin.utils.PathUtil import java.io.File import kotlin.util.measureTimeMillis @@ -153,14 +155,21 @@ class DokkaGenerator(val logger: DokkaLogger, val startAnalyse = System.currentTimeMillis() val options = DocumentationOptions(false, sourceLinks = sourceLinks, skipDeprecated = skipDeprecated) - val documentation = buildDocumentationModule(environment, moduleName, options, includes, { isSample(it) }, logger) + + val injector = Guice.createInjector(GuiceModule(this)) + val generator = injector.getInstance(Generator::class.java) + + val packageDocumentationBuilder = injector.getInstance(PackageDocumentationBuilder::class.java) + + val documentation = buildDocumentationModule(environment, moduleName, options, includes, { isSample(it) }, + packageDocumentationBuilder, logger) val timeAnalyse = System.currentTimeMillis() - startAnalyse logger.info("done in ${timeAnalyse / 1000} secs") val timeBuild = measureTimeMillis { logger.info("Generating pages... ") - Guice.createInjector(GuiceModule(this)).getInstance(Generator::class.java).buildAll(documentation) + generator.buildAll(documentation) } logger.info("done in ${timeBuild / 1000} secs") @@ -196,9 +205,13 @@ fun buildDocumentationModule(environment: AnalysisEnvironment, options: DocumentationOptions, includes: List<String> = listOf(), filesToDocumentFilter: (PsiFile) -> Boolean = { file -> true }, + packageDocumentationBuilder: PackageDocumentationBuilder? = null, logger: DokkaLogger): DocumentationModule { val documentation = environment.withContext { environment, resolutionFacade, session -> val fragmentFiles = environment.getSourceFiles().filter(filesToDocumentFilter) + val analyzer = resolutionFacade.getFrontendService(LazyTopDownAnalyzerForTopLevel::class.java) + analyzer.analyzeDeclarations(TopDownAnalysisMode.TopLevelDeclarations, fragmentFiles) + val fragments = fragmentFiles.map { session.getPackageFragment(it.packageFqName) }.filterNotNull().distinct() val refGraph = NodeReferenceGraph() @@ -210,7 +223,12 @@ fun buildDocumentationModule(environment: AnalysisEnvironment, val documentationModule = DocumentationModule(moduleName, packageDocs.moduleContent) with(documentationBuilder) { - documentationModule.appendFragments(fragments, packageDocs.packageContent) + if (packageDocumentationBuilder != null) { + documentationModule.appendFragments(fragments, packageDocs.packageContent, packageDocumentationBuilder) + } + else { + documentationModule.appendFragments(fragments, packageDocs.packageContent) + } } val javaFiles = environment.getJavaSourceFiles().filter(filesToDocumentFilter) diff --git a/test/src/TestAPI.kt b/test/src/TestAPI.kt index 59b6495b..c4be6623 100644 --- a/test/src/TestAPI.kt +++ b/test/src/TestAPI.kt @@ -16,6 +16,7 @@ import kotlin.test.fail public fun verifyModel(vararg roots: ContentRoot, withJdk: Boolean = false, withKotlinRuntime: Boolean = false, + packageDocumentationBuilder: PackageDocumentationBuilder? = null, verifier: (DocumentationModule) -> Unit) { val messageCollector = object : MessageCollector { override fun report(severity: CompilerMessageSeverity, message: String, location: CompilerMessageLocation) { @@ -46,7 +47,9 @@ public fun verifyModel(vararg roots: ContentRoot, addRoots(roots.toList()) } val options = DocumentationOptions(includeNonPublic = true, skipEmptyPackages = false, sourceLinks = listOf<SourceLinkDefinition>()) - val documentation = buildDocumentationModule(environment, "test", options, logger = DokkaConsoleLogger) + val documentation = buildDocumentationModule(environment, "test", options, + packageDocumentationBuilder = packageDocumentationBuilder, + logger = DokkaConsoleLogger) verifier(documentation) Disposer.dispose(environment) } @@ -54,8 +57,13 @@ public fun verifyModel(vararg roots: ContentRoot, public fun verifyModel(source: String, withJdk: Boolean = false, withKotlinRuntime: Boolean = false, + packageDocumentationBuilder: PackageDocumentationBuilder? = null, verifier: (DocumentationModule) -> Unit) { - verifyModel(contentRootFromPath(source), withJdk = withJdk, withKotlinRuntime = withKotlinRuntime, verifier = verifier) + verifyModel(contentRootFromPath(source), + withJdk = withJdk, + withKotlinRuntime = withKotlinRuntime, + packageDocumentationBuilder = packageDocumentationBuilder, + verifier = verifier) } public fun verifyPackageMember(kotlinSource: String, diff --git a/test/src/model/KotlinAsJavaTest.kt b/test/src/model/KotlinAsJavaTest.kt new file mode 100644 index 00000000..25ee5fad --- /dev/null +++ b/test/src/model/KotlinAsJavaTest.kt @@ -0,0 +1,32 @@ +package org.jetbrains.dokka.tests + +import org.jetbrains.dokka.DocumentationModule +import org.jetbrains.dokka.DocumentationNode +import org.jetbrains.dokka.KotlinAsJavaDocumentationBuilder +import org.junit.Test +import kotlin.test.assertEquals + +class KotlinAsJavaTest { + @Test fun function() { + verifyModelAsJava("test/data/functions/function.kt") { model -> + val pkg = model.members.single() + + val facadeClass = pkg.members.single { it.name == "FunctionKt" } + assertEquals(DocumentationNode.Kind.Class, facadeClass.kind) + + val fn = facadeClass.members.single() + assertEquals("fn", fn.name) + assertEquals(DocumentationNode.Kind.CompanionObjectFunction, fn.kind) + } + } +} + +fun verifyModelAsJava(source: String, + withJdk: Boolean = false, + withKotlinRuntime: Boolean = false, + verifier: (DocumentationModule) -> Unit) { + verifyModel(source, + withJdk = withJdk, withKotlinRuntime = withKotlinRuntime, + packageDocumentationBuilder = KotlinAsJavaDocumentationBuilder(), + verifier = verifier) +} |