diff options
Diffstat (limited to 'core/src/main/kotlin/Kotlin')
4 files changed, 0 insertions, 1228 deletions
diff --git a/core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt b/core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt deleted file mode 100644 index 7c9f2d15..00000000 --- a/core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt +++ /dev/null @@ -1,188 +0,0 @@ -package org.jetbrains.dokka.Kotlin - -import com.google.inject.Inject -import com.intellij.psi.PsiDocCommentOwner -import com.intellij.psi.PsiNamedElement -import com.intellij.psi.util.PsiTreeUtil -import org.intellij.markdown.parser.LinkMap -import org.jetbrains.dokka.* -import org.jetbrains.dokka.Samples.SampleProcessingService -import org.jetbrains.kotlin.descriptors.* -import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny -import org.jetbrains.kotlin.idea.kdoc.findKDoc -import org.jetbrains.kotlin.incremental.components.NoLookupLocation -import org.jetbrains.kotlin.kdoc.parser.KDocKnownTag -import org.jetbrains.kotlin.kdoc.psi.api.KDoc -import org.jetbrains.kotlin.kdoc.psi.impl.KDocSection -import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag -import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor -import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor -import org.jetbrains.kotlin.name.FqName -import org.jetbrains.kotlin.psi.KtDeclaration -import org.jetbrains.kotlin.psi.KtElement -import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils -import org.jetbrains.kotlin.resolve.DescriptorUtils -import org.jetbrains.kotlin.resolve.annotations.argumentValue -import org.jetbrains.kotlin.resolve.constants.StringValue -import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe -import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter -import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered -import org.jetbrains.kotlin.resolve.source.PsiSourceElement - -class DescriptorDocumentationParser -@Inject constructor( - val options: DokkaConfiguration.PassConfiguration, - val logger: DokkaLogger, - val linkResolver: DeclarationLinkResolver, - val resolutionFacade: DokkaResolutionFacade, - val refGraph: NodeReferenceGraph, - val sampleService: SampleProcessingService, - val signatureProvider: KotlinElementSignatureProvider, - val externalDocumentationLinkResolver: ExternalDocumentationLinkResolver -) { - fun parseDocumentation( - descriptor: DeclarationDescriptor, - inline: Boolean = false, - isDefaultNoArgConstructor: Boolean = false - ): Content = - parseDocumentationAndDetails(descriptor, inline, isDefaultNoArgConstructor).first - - fun parseDocumentationAndDetails( - descriptor: DeclarationDescriptor, - inline: Boolean = false, - isDefaultNoArgConstructor: Boolean = false - ): Pair<Content, (DocumentationNode) -> Unit> { - if (descriptor is JavaClassDescriptor || descriptor is JavaCallableMemberDescriptor) { - return parseJavadoc(descriptor) - } - - val kdoc = descriptor.findKDoc() ?: findStdlibKDoc(descriptor) - if (kdoc == null) { - if (options.effectivePackageOptions(descriptor.fqNameSafe).reportUndocumented && !descriptor.isDeprecated() && - descriptor !is ValueParameterDescriptor && descriptor !is TypeParameterDescriptor && - descriptor !is PropertyAccessorDescriptor && !descriptor.isSuppressWarning()) { - logger.warn("No documentation for ${descriptor.signatureWithSourceLocation()}") - } - return Content.Empty to { node -> } - } - - val contextDescriptor = - (PsiTreeUtil.getParentOfType(kdoc, KDoc::class.java)?.context as? KtDeclaration) - ?.takeIf { it != descriptor.original.sourcePsi() } - ?.resolveToDescriptorIfAny() - ?: descriptor - - var kdocText = if (isDefaultNoArgConstructor) { - getConstructorTagContent(descriptor) ?: kdoc.getContent() - } else kdoc.getContent() - - // workaround for code fence parsing problem in IJ markdown parser - if (kdocText.endsWith("```") || kdocText.endsWith("~~~")) { - kdocText += "\n" - } - val tree = parseMarkdown(kdocText) - val linkMap = LinkMap.buildLinkMap(tree.node, kdocText) - val content = buildContent( - tree, - LinkResolver(linkMap) { href -> linkResolver.resolveContentLink(contextDescriptor, href) }, - inline - ) - if (kdoc is KDocSection) { - val tags = kdoc.getTags() - tags.forEach { - when (it.knownTag) { - KDocKnownTag.SAMPLE -> - content.append(sampleService.resolveSample(contextDescriptor, it.getSubjectName(), it)) - KDocKnownTag.SEE -> - content.addTagToSeeAlso(contextDescriptor, it) - else -> { - val section = content.addSection(javadocSectionDisplayName(it.name), it.getSubjectName()) - val sectionContent = it.getContent() - val markdownNode = parseMarkdown(sectionContent) - buildInlineContentTo( - markdownNode, - section, - LinkResolver(linkMap) { href -> linkResolver.resolveContentLink(contextDescriptor, href) }) - } - } - } - } - return content to { node -> } - } - - private fun getConstructorTagContent(descriptor: DeclarationDescriptor): String? { - return ((DescriptorToSourceUtils.descriptorToDeclaration(descriptor)?.navigationElement as? KtElement) as KtDeclaration).docComment?.findSectionByTag( - KDocKnownTag.CONSTRUCTOR - )?.getContent() - } - - - private fun DeclarationDescriptor.isSuppressWarning(): Boolean { - val suppressAnnotation = annotations.findAnnotation(FqName(Suppress::class.qualifiedName!!)) - return if (suppressAnnotation != null) { - @Suppress("UNCHECKED_CAST") - (suppressAnnotation.argumentValue("names")?.value as List<StringValue>).any { it.value == "NOT_DOCUMENTED" } - } else containingDeclaration?.isSuppressWarning() ?: false - } - - /** - * Special case for generating stdlib documentation (the Any class to which the override chain will resolve - * is not the same one as the Any class included in the source scope). - */ - fun findStdlibKDoc(descriptor: DeclarationDescriptor): KDocTag? { - if (descriptor !is CallableMemberDescriptor) { - return null - } - val name = descriptor.name.asString() - if (name == "equals" || name == "hashCode" || name == "toString") { - var deepestDescriptor: CallableMemberDescriptor = descriptor - while (!deepestDescriptor.overriddenDescriptors.isEmpty()) { - deepestDescriptor = deepestDescriptor.overriddenDescriptors.first() - } - if (DescriptorUtils.getFqName(deepestDescriptor.containingDeclaration).asString() == "kotlin.Any") { - val anyClassDescriptors = resolutionFacade.resolveSession.getTopLevelClassifierDescriptors( - FqName.fromSegments(listOf("kotlin", "Any")), NoLookupLocation.FROM_IDE - ) - anyClassDescriptors.forEach { - val anyMethod = (it as ClassDescriptor).getMemberScope(listOf()) - .getDescriptorsFiltered(DescriptorKindFilter.FUNCTIONS) { it == descriptor.name } - .single() - val kdoc = anyMethod.findKDoc() - if (kdoc != null) { - return kdoc - } - } - } - } - return null - } - - fun parseJavadoc(descriptor: DeclarationDescriptor): Pair<Content, (DocumentationNode) -> Unit> { - val psi = ((descriptor as? DeclarationDescriptorWithSource)?.source as? PsiSourceElement)?.psi - if (psi is PsiDocCommentOwner) { - val parseResult = JavadocParser( - refGraph, - logger, - signatureProvider, - externalDocumentationLinkResolver - ).parseDocumentation(psi as PsiNamedElement) - return parseResult.content to { node -> } - } - return Content.Empty to { node -> } - } - - fun KDocSection.getTags(): Array<KDocTag> = PsiTreeUtil.getChildrenOfType(this, KDocTag::class.java) ?: arrayOf() - - private fun MutableContent.addTagToSeeAlso(descriptor: DeclarationDescriptor, seeTag: KDocTag) { - val subjectName = seeTag.getSubjectName() - if (subjectName != null) { - val seeSection = findSectionByTag("See Also") ?: addSection("See Also", null) - val link = linkResolver.resolveContentLink(descriptor, subjectName) - link.append(ContentText(subjectName)) - val para = ContentParagraph() - para.append(link) - seeSection.append(para) - } - } - -} diff --git a/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt b/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt deleted file mode 100644 index 6d258564..00000000 --- a/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt +++ /dev/null @@ -1,534 +0,0 @@ -package org.jetbrains.dokka - -import com.google.inject.Inject -import com.intellij.psi.PsiJavaFile -import org.jetbrains.dokka.DokkaConfiguration.PassConfiguration -import org.jetbrains.kotlin.builtins.KotlinBuiltIns -import org.jetbrains.kotlin.descriptors.* -import org.jetbrains.kotlin.idea.kdoc.findKDoc -import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi -import org.jetbrains.kotlin.kdoc.psi.impl.KDocSection -import org.jetbrains.kotlin.name.FqName -import org.jetbrains.kotlin.resolve.DescriptorUtils -import org.jetbrains.kotlin.resolve.descriptorUtil.* -import org.jetbrains.kotlin.resolve.findTopMostOverriddenDescriptors -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.types.* -import org.jetbrains.kotlin.types.typeUtil.immediateSupertypes -import org.jetbrains.kotlin.types.typeUtil.isAnyOrNullableAny -import org.jetbrains.kotlin.types.typeUtil.isTypeParameter -import org.jetbrains.kotlin.types.typeUtil.supertypes -import org.jetbrains.kotlin.util.supertypesWithAny -import kotlin.reflect.KClass -import com.google.inject.name.Named as GuiceNamed - -private fun isExtensionForExternalClass( - extensionFunctionDescriptor: DeclarationDescriptor, - extensionReceiverDescriptor: DeclarationDescriptor, - allFqNames: Collection<FqName> -): Boolean { - val extensionFunctionPackage = - DescriptorUtils.getParentOfType(extensionFunctionDescriptor, PackageFragmentDescriptor::class.java) - val extensionReceiverPackage = - DescriptorUtils.getParentOfType(extensionReceiverDescriptor, PackageFragmentDescriptor::class.java) - return extensionFunctionPackage != null && extensionReceiverPackage != null && - extensionFunctionPackage.fqName != extensionReceiverPackage.fqName && - extensionReceiverPackage.fqName !in allFqNames -} - -interface PackageDocumentationBuilder { - fun buildPackageDocumentation( - documentationBuilder: DocumentationBuilder, - packageName: FqName, - packageNode: DocumentationNodes.Package, - declarations: List<DeclarationDescriptor>, - allFqNames: Collection<FqName> - ) -} - -interface DefaultPlatformsProvider { - fun getDefaultPlatforms(descriptor: DeclarationDescriptor): List<String> -} - -val ignoredSupertypes = setOf( - "kotlin.Annotation", "kotlin.Enum", "kotlin.Any" -) - -class DocumentationBuilder -@Inject constructor( - val resolutionFacade: DokkaResolutionFacade, - val passConfiguration: DokkaConfiguration.PassConfiguration, - val logger: DokkaLogger -) { - - private fun DocumentationNodes.Class.appendSupertype(descriptor: ClassDescriptor, superType: KotlinType, backref: Boolean) { - val unwrappedType = superType.unwrap() - if (unwrappedType is AbbreviatedType) { - appendSupertype(descriptor, unwrappedType.abbreviation, backref) - } else { - appendType(unwrappedType, descriptor) - } - } - - private fun DocumentationNodes.Class.appendType( - kotlinType: KotlinType?, - descriptor: ClassDescriptor? - ) { - if (kotlinType == null) - return - (kotlinType.unwrap() as? AbbreviatedType)?.let { - return appendType(it.abbreviation, descriptor) - } - - if (kotlinType.isDynamic()) { - append(kind.createNode("dynamic", descriptor), RefKind.Detail) - return - } - - val classifierDescriptor = kotlinType.constructor.declarationDescriptor - val name = when (classifierDescriptor) { - is ClassDescriptor -> { - if (classifierDescriptor.isCompanionObject) { - classifierDescriptor.containingDeclaration.name.asString() + - "." + classifierDescriptor.name.asString() - } else { - classifierDescriptor.name.asString() - } - } - is Named -> classifierDescriptor.name.asString() - else -> "<anonymous>" - } - val node = kind.createNode(name, descriptor) - - append(node, RefKind.Detail) - for (typeArgument in kotlinType.arguments) { - node.appendProjection(typeArgument, null) - } - } - - fun DocumentationNode<*>.appendChild(descriptor: DeclarationDescriptor) { - if (!descriptor.isGenerated() && descriptor.isDocumented(passConfiguration)) { - val node = descriptor.build() - append(node, kind) - } - } - - fun DocumentationNode.appendMember(descriptor: DeclarationDescriptor) { - if (!descriptor.isGenerated() && descriptor.isDocumented(passConfiguration)) { - val existingNode = members.firstOrNull { it.descriptor?.fqNameSafe == descriptor.fqNameSafe } - if (existingNode != null) { - if (descriptor is ClassDescriptor) { - val membersToDocument = descriptor.collectMembersToDocument() - for ((memberDescriptor, _, _) in membersToDocument) { - if (memberDescriptor is ClassDescriptor) { - existingNode.appendMember(memberDescriptor) // recurse into nested classes - } else { - if (members.any { it.descriptor?.fqNameSafe == memberDescriptor.fqNameSafe }) { - existingNode.appendClassMember(memberDescriptor) - } - } - } - } - } else { - appendChild(descriptor, RefKind.Member) - } - } - } - - private fun DocumentationNode.appendClassMember(descriptor: DeclarationDescriptor) { - if (descriptor !is CallableMemberDescriptor || descriptor.kind != CallableMemberDescriptor.Kind.FAKE_OVERRIDE) { - val descriptorToUse = if (descriptor is ConstructorDescriptor) descriptor else descriptor.original - appendChild(descriptorToUse, RefKind.Member) - } - } - - fun DocumentationNodes.Module.appendFragments( - fragments: Collection<PackageFragmentDescriptor>, - packageDocumentationBuilder: PackageDocumentationBuilder - ) { - val allFqNames = fragments.filter { it.isDocumented(passConfiguration) }.map { it.fqName }.distinct() - - for (packageName in allFqNames) { - if (packageName.isRoot && !passConfiguration.includeRootPackage) continue - val declarations = fragments.filter { it.fqName == packageName } - .flatMap { it.getMemberScope().getContributedDescriptors() } - - if (passConfiguration.skipEmptyPackages && declarations.none { it.isDocumented(passConfiguration) }) continue - logger.info(" package $packageName: ${declarations.count()} declarations") - val packageNode = findOrCreatePackageNode(this, packageName.asString()) - packageDocumentationBuilder.buildPackageDocumentation( - this@DocumentationBuilder, packageName, packageNode, - declarations, allFqNames - ) - } - } - - fun findOrCreatePackageNode( - module: DocumentationNodes.Module, - packageName: String - ): DocumentationNode<*> { - val node = module?.member(DocumentationNodes.Package::class) ?: DocumentationNodes.Package(packageName) - if (module != null && node !in module.members) { - module.append(node, RefKind.Member) - } - return node - } - - fun propagateExtensionFunctionsToSubclasses( - fragments: Collection<PackageFragmentDescriptor>, - resolutionFacade: DokkaResolutionFacade - ) { - - 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 (passConfiguration.collectInheritedExtensionsFromLibraries) { - allPackageViewDescriptors.map { it.memberScope } - } else { - fragments.asSequence().map { it.getMemberScope() } - }.flatMap { - it.getDescriptorsFiltered( - DescriptorKindFilter.CALLABLES - ).asSequence() - } - - val allExtensionFunctions = - allDescriptors - .filterIsInstance<CallableMemberDescriptor>() - .filter { it.extensionReceiverParameter != null } - val extensionFunctionsByName = allExtensionFunctions.groupBy { it.name } - - fun isIgnoredReceiverType(type: KotlinType) = - type.isDynamic() || - type.isAnyOrNullableAny() || - (type.isTypeParameter() && type.immediateSupertypes().all { it.isAnyOrNullableAny() }) - - - for (extensionFunction in allExtensionFunctions) { - val extensionReceiverParameter = extensionFunction.extensionReceiverParameter!! - if (extensionFunction.dispatchReceiverParameter != null) continue - val possiblyShadowingFunctions = extensionFunctionsByName[extensionFunction.name] - ?.filter { fn -> fn.canShadow(extensionFunction) } - ?: emptyList() - - if (isIgnoredReceiverType(extensionReceiverParameter.type)) continue - } - } - - private fun CallableMemberDescriptor.canShadow(other: CallableMemberDescriptor): Boolean { - if (this == other) return false - if (this is PropertyDescriptor && other is PropertyDescriptor) { - return true - } - if (this is FunctionDescriptor && other is FunctionDescriptor) { - val parameters1 = valueParameters - val parameters2 = other.valueParameters - if (parameters1.size != parameters2.size) { - return false - } - for ((p1, p2) in parameters1 zip parameters2) { - if (p1.type != p2.type) { - return false - } - } - return true - } - return false - } - - fun DeclarationDescriptor.build(): DocumentationNode = when (this) { - is ClassifierDescriptor -> build() - is ConstructorDescriptor -> build() - is PropertyDescriptor -> build() - is FunctionDescriptor -> build() - is ValueParameterDescriptor -> build() - is ReceiverParameterDescriptor -> build() - else -> throw IllegalStateException("Descriptor $this is not known") - } - - fun ClassifierDescriptor.build(external: Boolean = false): DocumentationNode = when (this) { - is ClassDescriptor -> build(this, external) - is TypeAliasDescriptor -> build() - is TypeParameterDescriptor -> build() - else -> throw IllegalStateException("Descriptor $this is not known") - } - - fun TypeAliasDescriptor.build(): DocumentationNode { - val node = DocumentationNodes.TypeAlias(name.asString(), this) - node.appendType(underlyingType, this, DocumentationNodes.TypeAliasUnderlyingType::class) - return node - } - - fun ClassDescriptor.build(descriptor: DeclarationDescriptor, external: Boolean = false): DocumentationNode { - val node = when { - kind == ClassKind.OBJECT -> DocumentationNodes.Object(descriptor.name.asString(), descriptor) - kind == ClassKind.INTERFACE -> DocumentationNodes.Interface(descriptor.name.asString(), descriptor) - kind == ClassKind.ENUM_CLASS -> DocumentationNodes.Enum(descriptor.name.asString(), descriptor) - kind == ClassKind.ANNOTATION_CLASS -> DocumentationNodes.AnnotationClass(descriptor.name.asString(), descriptor) - kind == ClassKind.ENUM_ENTRY -> DocumentationNodes.EnumItem(descriptor.name.asString(), descriptor) - isSubclassOfThrowable() -> DocumentationNodes.Exception(descriptor.name.asString(), descriptor) - else -> DocumentationNodes.Class(descriptor.name.asString(), descriptor) - } - supertypesWithAnyPrecise().forEach { - node.appendSupertype(this, it, !external) - } - if (!external) { - for ((membersDescriptor, _, _) in collectMembersToDocument()) { - node.appendClassMember(membersDescriptor) - } - } - return node - } - - data class ClassMember( - val descriptor: DeclarationDescriptor, - val inheritedLinkKind: RefKind = RefKind.InheritedMember, - val extraModifier: String? = null - ) - - private fun ClassDescriptor.collectMembersToDocument(): List<ClassMember> { - val result = arrayListOf<ClassMember>() - if (kind != ClassKind.OBJECT && kind != ClassKind.ENUM_ENTRY) { - val constructorsToDocument = if (kind == ClassKind.ENUM_CLASS) - constructors.filter { it.valueParameters.size > 0 } - else - constructors - constructorsToDocument.mapTo(result) { ClassMember(it) } - } - - defaultType.memberScope.getContributedDescriptors() - .filter { it != companionObjectDescriptor } - .mapTo(result) { ClassMember(it) } - - staticScope.getContributedDescriptors() - .mapTo(result) { ClassMember(it, extraModifier = "static") } - - val companionObjectDescriptor = companionObjectDescriptor - if (companionObjectDescriptor != null && companionObjectDescriptor.isDocumented(passConfiguration)) { - val descriptors = companionObjectDescriptor.defaultType.memberScope.getContributedDescriptors() - val descriptorsToDocument = descriptors.filter { it !is CallableDescriptor || !it.isInheritedFromAny() } - descriptorsToDocument.mapTo(result) { - ClassMember(it, inheritedLinkKind = RefKind.InheritedCompanionObjectMember) - } - - if (companionObjectDescriptor.getAllSuperclassesWithoutAny().isNotEmpty() - || companionObjectDescriptor.getSuperInterfaces().isNotEmpty()) { - result += ClassMember(companionObjectDescriptor) - } - } - return result - } - - private fun CallableDescriptor.isInheritedFromAny(): Boolean { - return findTopMostOverriddenDescriptors().any { - DescriptorUtils.getFqNameSafe(it.containingDeclaration).asString() == "kotlin.Any" - } - } - - private fun ClassDescriptor.isSubclassOfThrowable(): Boolean = - defaultType.supertypes().any { it.constructor.declarationDescriptor == builtIns.throwable } - - fun ConstructorDescriptor.build(): DocumentationNode = - DocumentationNodes.Constructor(name.asString(), this) - - private fun CallableMemberDescriptor.inCompanionObject(): Boolean { - val containingDeclaration = containingDeclaration - if ((containingDeclaration as? ClassDescriptor)?.isCompanionObject == true) { - return true - } - val receiver = extensionReceiverParameter - return (receiver?.type?.constructor?.declarationDescriptor as? ClassDescriptor)?.isCompanionObject ?: false - } - - fun FunctionDescriptor.build(): DocumentationNode = - if (inCompanionObject()) - DocumentationNodes.CompanionObjectFunction(name.asString(),this) - else - DocumentationNodes.Function(name.asString(),this) - - fun PropertyDescriptor.build(): DocumentationNode = - DocumentationNodes.Property(name.asString(), this) - - fun ValueParameterDescriptor.build(): DocumentationNode = - DocumentationNodes.Parameter(name.asString(), this) - - fun TypeParameterDescriptor.build(): DocumentationNode = - DocumentationNodes.TypeParameter(name.asString(), this) - - fun ReceiverParameterDescriptor.build(): DocumentationNode = - DocumentationNodes.Receiver(name.asString(), this) -} - -fun DeclarationDescriptor.isDocumented(passConfiguration: DokkaConfiguration.PassConfiguration): Boolean { - return (passConfiguration.effectivePackageOptions(fqNameSafe).includeNonPublic - || this !is MemberDescriptor - || this.visibility.isPublicAPI) - && !isDocumentationSuppressed(passConfiguration) - && (!passConfiguration.effectivePackageOptions(fqNameSafe).skipDeprecated || !isDeprecated()) -} - -private fun DeclarationDescriptor.isGenerated() = - this is CallableMemberDescriptor && kind != CallableMemberDescriptor.Kind.DECLARATION - -class KotlinPackageDocumentationBuilder : PackageDocumentationBuilder { - - override fun buildPackageDocumentation( - documentationBuilder: DocumentationBuilder, - packageName: FqName, - packageNode: DocumentationNode, - declarations: List<DeclarationDescriptor>, - allFqNames: Collection<FqName> - ) { - declarations.forEach { descriptor -> - with(documentationBuilder) { - if (descriptor.isDocumented(passConfiguration)) { - packageNode.appendMember(descriptor) - } - } - } - } -} - -class KotlinJavaDocumentationBuilder -@Inject constructor( - val resolutionFacade: DokkaResolutionFacade, - val documentationBuilder: DocumentationBuilder, - val passConfiguration: DokkaConfiguration.PassConfiguration, - val logger: DokkaLogger -) : JavaDocumentationBuilder { - override fun appendFile(file: PsiJavaFile, module: DocumentationModule, packageContent: Map<String, Content>) { - val classDescriptors = file.classes.map { - it.getJavaClassDescriptor(resolutionFacade) - } - - if (classDescriptors.any { it != null && it.isDocumented(passConfiguration) }) { - val packageNode = documentationBuilder.findOrCreatePackageNode(module, file.packageName) - - for (descriptor in classDescriptors.filterNotNull()) { - with(documentationBuilder) { - packageNode.appendChild(descriptor, RefKind.Member) - } - } - } - } -} - -fun DeclarationDescriptor.isDocumentationSuppressed(passConfiguration: DokkaConfiguration.PassConfiguration): Boolean { - - if (passConfiguration.effectivePackageOptions(fqNameSafe).suppress) return true - - val path = this.findPsi()?.containingFile?.virtualFile?.path - if (path != null) { - if (path in passConfiguration.suppressedFiles) return true - } - - val doc = findKDoc() - if (doc is KDocSection && doc.findTagByName("suppress") != null) return true - - return hasSuppressDocTag(sourcePsi()) -} - -fun DeclarationDescriptor.sourcePsi() = - ((original as? DeclarationDescriptorWithSource)?.source as? PsiSourceElement)?.psi - -fun DeclarationDescriptor.isDeprecated(): Boolean = annotations.any { - DescriptorUtils.getFqName(it.type.constructor.declarationDescriptor!!).asString() == "kotlin.Deprecated" -} || (this is ConstructorDescriptor && containingDeclaration.isDeprecated()) - -fun DeclarationDescriptor.signature(): String { - if (this != original) return original.signature() - return when (this) { - is ClassDescriptor, - is PackageFragmentDescriptor, - is PackageViewDescriptor, - is TypeAliasDescriptor -> DescriptorUtils.getFqName(this).asString() - - is PropertyDescriptor -> containingDeclaration.signature() + "$" + name + receiverSignature() - is FunctionDescriptor -> containingDeclaration.signature() + "$" + name + parameterSignature() - is ValueParameterDescriptor -> containingDeclaration.signature() + "/" + name - is TypeParameterDescriptor -> containingDeclaration.signature() + "*" + name - is ReceiverParameterDescriptor -> containingDeclaration.signature() + "/" + name - else -> throw UnsupportedOperationException("Don't know how to calculate signature for $this") - } -} - -fun PropertyDescriptor.receiverSignature(): String { - val receiver = extensionReceiverParameter - if (receiver != null) { - return "#" + receiver.type.signature() - } - return "" -} - -fun CallableMemberDescriptor.parameterSignature(): String { - val params = valueParameters.map { it.type }.toMutableList() - val extensionReceiver = extensionReceiverParameter - if (extensionReceiver != null) { - params.add(0, extensionReceiver.type) - } - return params.joinToString(prefix = "(", postfix = ")") { it.signature() } -} - -fun KotlinType.signature(): String { - val visited = hashSetOf<KotlinType>() - - fun KotlinType.signatureRecursive(): String { - if (this in visited) { - return "" - } - visited.add(this) - - val declarationDescriptor = constructor.declarationDescriptor ?: return "<null>" - val typeName = DescriptorUtils.getFqName(declarationDescriptor).asString() - if (arguments.isEmpty()) { - return typeName - } - return typeName + arguments.joinToString(prefix = "((", postfix = "))") { it.type.signatureRecursive() } - } - - return signatureRecursive() -} - -fun DeclarationDescriptor.signatureWithSourceLocation(): String { - val signature = signature() - val sourceLocation = sourceLocation() - return if (sourceLocation != null) "$signature ($sourceLocation)" else signature -} - -fun DeclarationDescriptor.sourceLocation(): String? { - val psi = sourcePsi() - if (psi != null) { - val fileName = psi.containingFile.name - val lineNumber = psi.lineNumber() - return if (lineNumber != null) "$fileName:$lineNumber" else fileName - } - return null -} - -fun ClassDescriptor.supertypesWithAnyPrecise(): Collection<KotlinType> { - if (KotlinBuiltIns.isAny(this)) { - return emptyList() - } - return typeConstructor.supertypesWithAny() -} - -fun PassConfiguration.effectivePackageOptions(pack: String): DokkaConfiguration.PackageOptions { - val rootPackageOptions = PackageOptionsImpl("", includeNonPublic, reportUndocumented, skipDeprecated, false) - return perPackageOptions.firstOrNull { pack == it.prefix || pack.startsWith(it.prefix + ".") } ?: rootPackageOptions -} - -fun PassConfiguration.effectivePackageOptions(pack: FqName): DokkaConfiguration.PackageOptions = - effectivePackageOptions(pack.asString()) - diff --git a/core/src/main/kotlin/Kotlin/KotlinElementSignatureProvider.kt b/core/src/main/kotlin/Kotlin/KotlinElementSignatureProvider.kt deleted file mode 100644 index c7187b23..00000000 --- a/core/src/main/kotlin/Kotlin/KotlinElementSignatureProvider.kt +++ /dev/null @@ -1,33 +0,0 @@ -package org.jetbrains.dokka - -import com.intellij.psi.PsiElement -import com.intellij.psi.PsiMember -import com.intellij.psi.PsiPackage -import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade -import org.jetbrains.kotlin.asJava.elements.KtLightElement -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.name.FqName -import org.jetbrains.kotlin.resolve.BindingContext -import javax.inject.Inject - -class KotlinElementSignatureProvider @Inject constructor( - val resolutionFacade: DokkaResolutionFacade -) : ElementSignatureProvider { - override fun signature(forPsi: PsiElement): String { - return forPsi.extractDescriptor(resolutionFacade) - ?.let { signature(it) } - ?: run { "no desc for $forPsi in ${(forPsi as? PsiMember)?.containingClass}" } - } - - override fun signature(forDesc: DeclarationDescriptor): String = forDesc.signature() -} - - -fun PsiElement.extractDescriptor(resolutionFacade: DokkaResolutionFacade): DeclarationDescriptor? = - when (val forPsi = this) { - is KtLightClassForFacade -> resolutionFacade.moduleDescriptor.getPackage(forPsi.fqName) - is KtLightElement<*, *> -> (forPsi.kotlinOrigin!!).extractDescriptor(resolutionFacade) - is PsiPackage -> resolutionFacade.moduleDescriptor.getPackage(FqName(forPsi.qualifiedName)) - is PsiMember -> forPsi.getJavaOrKotlinMemberDescriptor(resolutionFacade) - else -> resolutionFacade.resolveSession.bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, forPsi] - } diff --git a/core/src/main/kotlin/Kotlin/KotlinLanguageService.kt b/core/src/main/kotlin/Kotlin/KotlinLanguageService.kt deleted file mode 100644 index 7310610f..00000000 --- a/core/src/main/kotlin/Kotlin/KotlinLanguageService.kt +++ /dev/null @@ -1,473 +0,0 @@ -package org.jetbrains.dokka - -import org.jetbrains.dokka.LanguageService.RenderMode - -/** - * Implements [LanguageService] and provides rendering of symbols in Kotlin language - */ -class KotlinLanguageService : CommonLanguageService() { - override fun showModifierInSummary(node: DocumentationNode): Boolean { - return node.name !in fullOnlyModifiers - } - - private val fullOnlyModifiers = - setOf("public", "protected", "private", "internal", "inline", "noinline", "crossinline", "reified") - - override fun render(node: DocumentationNode, renderMode: RenderMode): ContentNode { - return content { - when (node.kind) { - NodeKind.Package -> if (renderMode == RenderMode.FULL) renderPackage(node) - in NodeKind.classLike -> renderClass(node, renderMode) - - NodeKind.EnumItem, - NodeKind.ExternalClass -> if (renderMode == RenderMode.FULL) identifier(node.name) - - NodeKind.Parameter -> renderParameter(node, renderMode) - NodeKind.TypeParameter -> renderTypeParameter(node, renderMode) - NodeKind.Type, - NodeKind.UpperBound -> renderType(node, renderMode) - - NodeKind.Modifier -> renderModifier(this, node, renderMode) - NodeKind.Constructor, - NodeKind.Function, - NodeKind.CompanionObjectFunction -> renderFunction(node, renderMode) - NodeKind.Property, - NodeKind.CompanionObjectProperty -> renderProperty(node, renderMode) - else -> identifier(node.name) - } - } - } - - - override fun summarizeSignatures(nodes: List<DocumentationNode>): ContentNode? { - if (nodes.size < 2) return null - val receiverKind = nodes.getReceiverKind() ?: return null - val functionWithTypeParameter = nodes.firstOrNull { it.details(NodeKind.TypeParameter).any() } ?: return null - return content { - val typeParameter = functionWithTypeParameter.details(NodeKind.TypeParameter).first() - if (functionWithTypeParameter.kind == NodeKind.Function) { - renderFunction( - functionWithTypeParameter, - RenderMode.SUMMARY, - SummarizingMapper(receiverKind, typeParameter.name) - ) - } else { - renderProperty( - functionWithTypeParameter, - RenderMode.SUMMARY, - SummarizingMapper(receiverKind, typeParameter.name) - ) - } - } - } - - private fun List<DocumentationNode>.getReceiverKind(): ReceiverKind? { - val qNames = mapNotNull { it.getReceiverQName() } - if (qNames.size != size) - return null - - return ReceiverKind.values().firstOrNull { kind -> qNames.all { it in kind.classes } } - } - - private fun DocumentationNode.getReceiverQName(): String? { - if (kind != NodeKind.Function && kind != NodeKind.Property) return null - val receiver = details(NodeKind.Receiver).singleOrNull() ?: return null - return receiver.detail(NodeKind.Type).qualifiedNameFromType() - } - - companion object { - private val arrayClasses = setOf( - "kotlin.Array", - "kotlin.BooleanArray", - "kotlin.ByteArray", - "kotlin.CharArray", - "kotlin.ShortArray", - "kotlin.IntArray", - "kotlin.LongArray", - "kotlin.FloatArray", - "kotlin.DoubleArray" - ) - - private val arrayOrListClasses = setOf("kotlin.List") + arrayClasses - - private val iterableClasses = setOf( - "kotlin.Collection", - "kotlin.Sequence", - "kotlin.Iterable", - "kotlin.Map", - "kotlin.String", - "kotlin.CharSequence" - ) + arrayOrListClasses - } - - private enum class ReceiverKind(val receiverName: String, val classes: Collection<String>) { - ARRAY("any_array", arrayClasses), - ARRAY_OR_LIST("any_array_or_list", arrayOrListClasses), - ITERABLE("any_iterable", iterableClasses), - } - - interface SignatureMapper { - fun renderReceiver(receiver: DocumentationNode, to: ContentBlock) - } - - private class SummarizingMapper(val kind: ReceiverKind, val typeParameterName: String) : SignatureMapper { - override fun renderReceiver(receiver: DocumentationNode, to: ContentBlock) { - to.append(ContentIdentifier(kind.receiverName, IdentifierKind.SummarizedTypeName)) - to.text("<$typeParameterName>") - } - } - - private fun ContentBlock.renderFunctionalTypeParameterName(node: DocumentationNode, renderMode: RenderMode) { - node.references(RefKind.HiddenAnnotation).map { it.to } - .find { it.name == "ParameterName" }?.let { - val parameterNameValue = it.detail(NodeKind.Parameter).detail(NodeKind.Value) - identifier(parameterNameValue.name.removeSurrounding("\""), IdentifierKind.ParameterName) - symbol(":") - nbsp() - } - } - - private fun ContentBlock.renderFunctionalType(node: DocumentationNode, renderMode: RenderMode) { - var typeArguments = node.details(NodeKind.Type) - - if (node.name.startsWith("Suspend")) { - keyword("suspend ") - } - - // lambda - val isExtension = node.annotations.any { it.name == "ExtensionFunctionType" } - if (isExtension) { - renderType(typeArguments.first(), renderMode) - symbol(".") - typeArguments = typeArguments.drop(1) - } - symbol("(") - renderList(typeArguments.take(typeArguments.size - 1), noWrap = true) { - renderFunctionalTypeParameterName(it, renderMode) - renderType(it, renderMode) - } - symbol(")") - nbsp() - symbol("->") - nbsp() - renderType(typeArguments.last(), renderMode) - - } - - private fun DocumentationNode.isFunctionalType(): Boolean { - val typeArguments = details(NodeKind.Type) - val functionalTypeName = "Function${typeArguments.count() - 1}" - val suspendFunctionalTypeName = "Suspend$functionalTypeName" - return name == functionalTypeName || name == suspendFunctionalTypeName - } - - private fun ContentBlock.renderType(node: DocumentationNode, renderMode: RenderMode) { - if (node.name == "dynamic") { - keyword("dynamic") - return - } - - val nullabilityModifier = node.detailOrNull(NodeKind.NullabilityModifier) - - if (node.isFunctionalType()) { - if (nullabilityModifier != null) { - symbol("(") - renderFunctionalType(node, renderMode) - symbol(")") - symbol(nullabilityModifier.name) - } else { - renderFunctionalType(node, renderMode) - } - return - } - if (renderMode == RenderMode.FULL) { - renderAnnotationsForNode(node) - } - renderModifiersForNode(node, renderMode, true) - renderLinked(this, node) { - identifier(it.typeDeclarationClass?.classNodeNameWithOuterClass() ?: it.name, IdentifierKind.TypeName) - } - val typeArguments = node.details(NodeKind.Type) - if (typeArguments.isNotEmpty()) { - symbol("<") - renderList(typeArguments, noWrap = true) { - renderType(it, renderMode) - } - symbol(">") - } - - nullabilityModifier ?.apply { - symbol(nullabilityModifier.name) - } - } - - override fun renderModifier( - block: ContentBlock, - node: DocumentationNode, - renderMode: RenderMode, - nowrap: Boolean - ) { - when (node.name) { - "final", "public", "var", "expect", "actual", "external" -> { - } - else -> { - if (showModifierInSummary(node) || renderMode == RenderMode.FULL) { - super.renderModifier(block, node, renderMode, nowrap) - } - } - } - } - - private fun ContentBlock.renderTypeParameter(node: DocumentationNode, renderMode: RenderMode) { - renderModifiersForNode(node, renderMode, true) - - identifier(node.name) - - val constraints = node.details(NodeKind.UpperBound) - if (constraints.size == 1) { - nbsp() - symbol(":") - nbsp() - renderList(constraints, noWrap = true) { - renderType(it, renderMode) - } - } - } - - private fun ContentBlock.renderParameter(node: DocumentationNode, renderMode: RenderMode) { - if (renderMode == RenderMode.FULL) { - renderAnnotationsForNode(node) - } - renderModifiersForNode(node, renderMode) - identifier(node.name, IdentifierKind.ParameterName, node.detailOrNull(NodeKind.Signature)?.name) - symbol(":") - nbsp() - val parameterType = node.detail(NodeKind.Type) - renderType(parameterType, renderMode) - val valueNode = node.details(NodeKind.Value).firstOrNull() - if (valueNode != null) { - nbsp() - symbol("=") - nbsp() - text(valueNode.name) - } - } - - private fun ContentBlock.renderTypeParametersForNode(node: DocumentationNode, renderMode: RenderMode) { - val typeParameters = node.details(NodeKind.TypeParameter) - if (typeParameters.any()) { - symbol("<") - renderList(typeParameters) { - renderTypeParameter(it, renderMode) - } - symbol(">") - } - } - - private fun ContentBlock.renderExtraTypeParameterConstraints(node: DocumentationNode, renderMode: RenderMode) { - val parametersWithMultipleConstraints = - node.details(NodeKind.TypeParameter).filter { it.details(NodeKind.UpperBound).size > 1 } - val parametersWithConstraints = parametersWithMultipleConstraints - .flatMap { parameter -> - parameter.details(NodeKind.UpperBound).map { constraint -> parameter to constraint } - } - if (parametersWithMultipleConstraints.isNotEmpty()) { - keyword(" where ") - renderList(parametersWithConstraints) { - identifier(it.first.name) - nbsp() - symbol(":") - nbsp() - renderType(it.second, renderMode) - } - } - } - - private fun ContentBlock.renderSupertypesForNode(node: DocumentationNode, renderMode: RenderMode) { - val supertypes = node.details(NodeKind.Supertype).filterNot { it.qualifiedNameFromType() in ignoredSupertypes } - if (supertypes.any()) { - nbsp() - symbol(":") - nbsp() - renderList(supertypes) { - indentedSoftLineBreak() - renderType(it, renderMode) - } - } - } - - private fun ContentBlock.renderAnnotationsForNode(node: DocumentationNode) { - node.annotations.forEach { - renderAnnotation(it) - } - } - - private fun ContentBlock.renderAnnotation(node: DocumentationNode) { - identifier("@" + node.name, IdentifierKind.AnnotationName) - val parameters = node.details(NodeKind.Parameter) - if (!parameters.isEmpty()) { - symbol("(") - renderList(parameters) { - text(it.detail(NodeKind.Value).name) - } - symbol(")") - } - text(" ") - } - - private fun ContentBlock.renderClass(node: DocumentationNode, renderMode: RenderMode) { - if (renderMode == RenderMode.FULL) { - renderAnnotationsForNode(node) - } - renderModifiersForNode(node, renderMode) - when (node.kind) { - NodeKind.Class, - NodeKind.AnnotationClass, - NodeKind.Exception, - NodeKind.Enum -> keyword("class ") - NodeKind.Interface -> keyword("interface ") - NodeKind.EnumItem -> keyword("enum val ") - NodeKind.Object -> keyword("object ") - NodeKind.TypeAlias -> keyword("typealias ") - else -> throw IllegalArgumentException("Node $node is not a class-like object") - } - - identifierOrDeprecated(node) - renderTypeParametersForNode(node, renderMode) - renderSupertypesForNode(node, renderMode) - renderExtraTypeParameterConstraints(node, renderMode) - - if (node.kind == NodeKind.TypeAlias) { - nbsp() - symbol("=") - nbsp() - renderType(node.detail(NodeKind.TypeAliasUnderlyingType), renderMode) - } - } - - private fun ContentBlock.renderFunction( - node: DocumentationNode, - renderMode: RenderMode, - signatureMapper: SignatureMapper? = null - ) { - if (renderMode == RenderMode.FULL) { - renderAnnotationsForNode(node) - } - renderModifiersForNode(node, renderMode) - when (node.kind) { - NodeKind.Constructor -> identifier(node.owner!!.name) - NodeKind.Function, - NodeKind.CompanionObjectFunction -> keyword("fun ") - else -> throw IllegalArgumentException("Node $node is not a function-like object") - } - renderTypeParametersForNode(node, renderMode) - if (node.details(NodeKind.TypeParameter).any()) { - text(" ") - } - - renderReceiver(node, renderMode, signatureMapper) - - if (node.kind != NodeKind.Constructor) - identifierOrDeprecated(node) - - symbol("(") - val parameters = node.details(NodeKind.Parameter) - renderList(parameters) { - indentedSoftLineBreak() - renderParameter(it, renderMode) - } - if (needReturnType(node)) { - if (parameters.isNotEmpty()) { - softLineBreak() - } - symbol(")") - symbol(": ") - renderType(node.detail(NodeKind.Type), renderMode) - } else { - symbol(")") - } - renderExtraTypeParameterConstraints(node, renderMode) - } - - private fun ContentBlock.renderReceiver( - node: DocumentationNode, - renderMode: RenderMode, - signatureMapper: SignatureMapper? - ) { - val receiver = node.details(NodeKind.Receiver).singleOrNull() - if (receiver != null) { - if (signatureMapper != null) { - signatureMapper.renderReceiver(receiver, this) - } else { - val type = receiver.detail(NodeKind.Type) - - if (type.isFunctionalType()) { - symbol("(") - renderFunctionalType(type, renderMode) - symbol(")") - } else { - renderType(type, renderMode) - } - } - symbol(".") - } - } - - private fun needReturnType(node: DocumentationNode) = when (node.kind) { - NodeKind.Constructor -> false - else -> !node.isUnitReturnType() - } - - fun DocumentationNode.isUnitReturnType(): Boolean = - detail(NodeKind.Type).hiddenLinks.firstOrNull()?.qualifiedName() == "kotlin.Unit" - - private fun ContentBlock.renderProperty( - node: DocumentationNode, - renderMode: RenderMode, - signatureMapper: SignatureMapper? = null - ) { - if (renderMode == RenderMode.FULL) { - renderAnnotationsForNode(node) - } - renderModifiersForNode(node, renderMode) - when (node.kind) { - NodeKind.Property, - NodeKind.CompanionObjectProperty -> keyword("${node.getPropertyKeyword()} ") - else -> throw IllegalArgumentException("Node $node is not a property") - } - renderTypeParametersForNode(node, renderMode) - if (node.details(NodeKind.TypeParameter).any()) { - text(" ") - } - - renderReceiver(node, renderMode, signatureMapper) - - identifierOrDeprecated(node) - symbol(": ") - renderType(node.detail(NodeKind.Type), renderMode) - renderExtraTypeParameterConstraints(node, renderMode) - } - - fun DocumentationNode.getPropertyKeyword() = - if (details(NodeKind.Modifier).any { it.name == "var" }) "var" else "val" - - fun ContentBlock.identifierOrDeprecated(node: DocumentationNode) { - if (node.deprecation != null) { - val strike = ContentStrikethrough() - strike.identifier(node.name) - append(strike) - } else { - identifier(node.name) - } - } -} - -fun DocumentationNode.qualifiedNameFromType(): String { - return details.firstOrNull { it.kind == NodeKind.QualifiedName }?.name - ?: (links.firstOrNull() ?: hiddenLinks.firstOrNull())?.qualifiedName() - ?: name -} - - -val DocumentationNode.typeDeclarationClass - get() = (links.firstOrNull { it.kind in NodeKind.classLike } ?: externalType) |