From e4b2ae90bf0e84f76ceb7c56b7c128d28adad917 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 30 Oct 2015 18:43:48 +0100 Subject: initial support for generating javadoc from Kotlin light classes --- src/Kotlin/DocumentationBuilder.kt | 145 +++++++++++++++++++++---------------- 1 file changed, 83 insertions(+), 62 deletions(-) (limited to 'src/Kotlin/DocumentationBuilder.kt') 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, + 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) { 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): 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, - packageContent: Map) { - val descriptors = hashMapOf>() - 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, + 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() - 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, + options: DocumentationOptions, + refGraph: NodeReferenceGraph, logger: DokkaLogger) { + val externalClassNodes = hashMapOf() + 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): 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 +} + -- cgit