aboutsummaryrefslogtreecommitdiff
path: root/core/src/main/kotlin/Kotlin
diff options
context:
space:
mode:
authorSimon Ogorodnik <Simon.Ogorodnik@jetbrains.com>2019-03-18 22:05:22 +0300
committerSimon Ogorodnik <Simon.Ogorodnik@jetbrains.com>2019-03-18 22:05:22 +0300
commitfd2f36301e95f8d100e1c2b942f1590144d8c6c2 (patch)
treedcbf109f14de5301848c29e9721c8e0af6881b3e /core/src/main/kotlin/Kotlin
parentf2359e05347708e625d5a6b339010cda2adc30de (diff)
parent4b22ebab09ce3b934443d063df6b905e5347c390 (diff)
downloaddokka-fd2f36301e95f8d100e1c2b942f1590144d8c6c2.tar.gz
dokka-fd2f36301e95f8d100e1c2b942f1590144d8c6c2.tar.bz2
dokka-fd2f36301e95f8d100e1c2b942f1590144d8c6c2.zip
Merge branch 'dev'
Diffstat (limited to 'core/src/main/kotlin/Kotlin')
-rw-r--r--core/src/main/kotlin/Kotlin/DeclarationLinkResolver.kt9
-rw-r--r--core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt32
-rw-r--r--core/src/main/kotlin/Kotlin/DocumentationBuilder.kt377
-rw-r--r--core/src/main/kotlin/Kotlin/ExternalDocumentationLinkResolver.kt61
-rw-r--r--core/src/main/kotlin/Kotlin/KotlinAsJavaDescriptorSignatureProvider.kt22
-rw-r--r--core/src/main/kotlin/Kotlin/KotlinAsJavaDocumentationBuilder.kt5
-rw-r--r--core/src/main/kotlin/Kotlin/KotlinAsJavaElementSignatureProvider.kt25
-rw-r--r--core/src/main/kotlin/Kotlin/KotlinDescriptorSignatureProvider.kt9
-rw-r--r--core/src/main/kotlin/Kotlin/KotlinElementSignatureProvider.kt34
-rw-r--r--core/src/main/kotlin/Kotlin/KotlinLanguageService.kt217
10 files changed, 507 insertions, 284 deletions
diff --git a/core/src/main/kotlin/Kotlin/DeclarationLinkResolver.kt b/core/src/main/kotlin/Kotlin/DeclarationLinkResolver.kt
index ffef399d..d73bef4a 100644
--- a/core/src/main/kotlin/Kotlin/DeclarationLinkResolver.kt
+++ b/core/src/main/kotlin/Kotlin/DeclarationLinkResolver.kt
@@ -1,13 +1,10 @@
package org.jetbrains.dokka
import com.google.inject.Inject
-import org.jetbrains.dokka.Model.DescriptorSignatureProvider
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.TypeAliasDescriptor
import org.jetbrains.kotlin.idea.kdoc.resolveKDocLink
-import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyPrivateApi
-import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyPublicApi
class DeclarationLinkResolver
@Inject constructor(val resolutionFacade: DokkaResolutionFacade,
@@ -15,7 +12,7 @@ class DeclarationLinkResolver
val logger: DokkaLogger,
val options: DocumentationOptions,
val externalDocumentationLinkResolver: ExternalDocumentationLinkResolver,
- val descriptorSignatureProvider: DescriptorSignatureProvider) {
+ val elementSignatureProvider: ElementSignatureProvider) {
fun tryResolveContentLink(fromDescriptor: DeclarationDescriptor, href: String): ContentBlock? {
@@ -34,14 +31,14 @@ class DeclarationLinkResolver
if (externalHref != null) {
return ContentExternalLink(externalHref)
}
- val signature = descriptorSignatureProvider.signature(symbol)
+ val signature = elementSignatureProvider.signature(symbol)
val referencedAt = fromDescriptor.signatureWithSourceLocation()
return ContentNodeLazyLink(href, { ->
val target = refGraph.lookup(signature)
if (target == null) {
- logger.warn("Can't find node by signature $signature, referenced at $referencedAt")
+ logger.warn("Can't find node by signature `$signature`, referenced at $referencedAt")
}
target
})
diff --git a/core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt b/core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt
index 6e44df74..d1f98184 100644
--- a/core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt
+++ b/core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt
@@ -19,6 +19,8 @@ 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
@@ -33,12 +35,15 @@ class DescriptorDocumentationParser
val linkResolver: DeclarationLinkResolver,
val resolutionFacade: DokkaResolutionFacade,
val refGraph: NodeReferenceGraph,
- val sampleService: SampleProcessingService)
+ val sampleService: SampleProcessingService,
+ val signatureProvider: KotlinElementSignatureProvider,
+ val externalDocumentationLinkResolver: ExternalDocumentationLinkResolver
+)
{
- fun parseDocumentation(descriptor: DeclarationDescriptor, inline: Boolean = false): Content =
- parseDocumentationAndDetails(descriptor, inline).first
+ fun parseDocumentation(descriptor: DeclarationDescriptor, inline: Boolean = false, isDefaultNoArgConstructor: Boolean = false): Content =
+ parseDocumentationAndDetails(descriptor, inline, isDefaultNoArgConstructor).first
- fun parseDocumentationAndDetails(descriptor: DeclarationDescriptor, inline: Boolean = false): Pair<Content, (DocumentationNode) -> Unit> {
+ fun parseDocumentationAndDetails(descriptor: DeclarationDescriptor, inline: Boolean = false, isDefaultNoArgConstructor: Boolean = false): Pair<Content, (DocumentationNode) -> Unit> {
if (descriptor is JavaClassDescriptor || descriptor is JavaCallableMemberDescriptor) {
return parseJavadoc(descriptor)
}
@@ -59,7 +64,10 @@ class DescriptorDocumentationParser
?.resolveToDescriptorIfAny()
?: descriptor
- var kdocText = kdoc.getContent()
+ 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"
@@ -87,6 +95,13 @@ class DescriptorDocumentationParser
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) {
@@ -129,7 +144,12 @@ class DescriptorDocumentationParser
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).parseDocumentation(psi as PsiNamedElement)
+ val parseResult = JavadocParser(
+ refGraph,
+ logger,
+ signatureProvider,
+ externalDocumentationLinkResolver
+ ).parseDocumentation(psi as PsiNamedElement)
return parseResult.content to { node ->
parseResult.deprecatedContent?.let {
val deprecationNode = DocumentationNode("", it, NodeKind.Modifier)
diff --git a/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt b/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt
index 7b50fff5..38804e39 100644
--- a/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt
+++ b/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt
@@ -11,25 +11,29 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotated
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
-import org.jetbrains.kotlin.load.java.structure.impl.JavaClassImpl
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtModifierListOwner
import org.jetbrains.kotlin.psi.KtParameter
+import org.jetbrains.kotlin.psi.addRemoveModifier.MODIFIERS_ORDER
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.constants.ConstantValue
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 org.jetbrains.kotlin.util.supertypesWithAny
import java.io.File
import java.nio.file.Path
import java.nio.file.Paths
@@ -50,10 +54,12 @@ class DocumentationOptions(val outputDir: String,
perPackageOptions: List<PackageOptions> = emptyList(),
externalDocumentationLinks: List<ExternalDocumentationLink> = emptyList(),
noStdlibLink: Boolean,
+ noJdkLink: Boolean = false,
val languageVersion: String?,
val apiVersion: String?,
cacheRoot: String? = null,
- val suppressedFiles: Set<File> = emptySet()) {
+ val suppressedFiles: Set<File> = emptySet(),
+ 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")
@@ -66,7 +72,10 @@ class DocumentationOptions(val outputDir: String,
fun effectivePackageOptions(pack: FqName): PackageOptions = effectivePackageOptions(pack.asString())
val defaultLinks = run {
- val links = mutableListOf(ExternalDocumentationLink.Builder("http://docs.oracle.com/javase/$jdkVersion/docs/api/").build())
+ val links = mutableListOf<ExternalDocumentationLink>()
+ if (!noJdkLink)
+ links += ExternalDocumentationLink.Builder("https://docs.oracle.com/javase/$jdkVersion/docs/api/").build()
+
if (!noStdlibLink)
links += ExternalDocumentationLink.Builder("https://kotlinlang.org/api/latest/jvm/stdlib/").build()
links
@@ -103,6 +112,10 @@ 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 descriptorDocumentationParser: DescriptorDocumentationParser,
@@ -134,8 +147,20 @@ class DocumentationBuilder
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)
@@ -169,27 +194,20 @@ class DocumentationBuilder
appendTextNode(modifier, NodeKind.Modifier)
}
- fun DocumentationNode.appendSupertype(descriptor: ClassDescriptor, superType: KotlinType) {
+ fun DocumentationNode.appendSupertype(descriptor: ClassDescriptor, superType: KotlinType, backref: Boolean) {
val unwrappedType = superType.unwrap()
if (unwrappedType is AbbreviatedType) {
- appendSupertype(descriptor, unwrappedType.abbreviation)
- } else if (!ignoreSupertype(unwrappedType)) {
+ appendSupertype(descriptor, unwrappedType.abbreviation, backref)
+ } else {
appendType(unwrappedType, NodeKind.Supertype)
val superclass = unwrappedType.constructor.declarationDescriptor
- link(superclass, descriptor, RefKind.Inheritor)
+ if (backref) {
+ link(superclass, descriptor, RefKind.Inheritor)
+ }
link(descriptor, superclass, RefKind.Superclass)
}
}
- private fun ignoreSupertype(superType: KotlinType): Boolean {
- val superClass = superType.constructor.declarationDescriptor as? ClassDescriptor
- if (superClass != null) {
- val fqName = DescriptorUtils.getFqNameSafe(superClass).asString()
- return fqName == "kotlin.Annotation" || fqName == "kotlin.Enum" || fqName == "kotlin.Any"
- }
- return false
- }
-
fun DocumentationNode.appendProjection(projection: TypeProjection, kind: NodeKind = NodeKind.Type) {
if (projection.isStarProjection) {
appendTextNode("*", NodeKind.Type)
@@ -227,19 +245,39 @@ class DocumentationBuilder
if (prefix != "") {
node.appendTextNode(prefix, NodeKind.Modifier)
}
- if (kotlinType.isMarkedNullable) {
+ if (kotlinType.isNullabilityFlexible()) {
+ node.appendTextNode("!", NodeKind.NullabilityModifier)
+ } else if (kotlinType.isMarkedNullable) {
node.appendTextNode("?", NodeKind.NullabilityModifier)
}
if (classifierDescriptor != null) {
- val externalLink = linkResolver.externalDocumentationLinkResolver.buildExternalDocumentationLink(classifierDescriptor)
+ val externalLink =
+ linkResolver.externalDocumentationLinkResolver.buildExternalDocumentationLink(classifierDescriptor)
if (externalLink != null) {
- node.append(DocumentationNode(externalLink, Content.Empty, NodeKind.ExternalLink), RefKind.Link)
+ 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(
+ DocumentationNode(
+ classifierDescriptor.fqNameUnsafe.asString(),
+ Content.Empty,
+ NodeKind.QualifiedName
+ ), RefKind.Detail
+ )
}
}
+
append(node, RefKind.Detail)
node.appendAnnotations(kotlinType)
for (typeArgument in kotlinType.arguments) {
@@ -273,6 +311,17 @@ class DocumentationBuilder
}
}
+ 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)
@@ -284,7 +333,11 @@ class DocumentationBuilder
fun DocumentationNode.appendModifiers(descriptor: DeclarationDescriptor) {
val psi = (descriptor as DeclarationDescriptorWithSource).source.getPsi() as? KtModifierListOwner ?: return
- KtTokens.MODIFIER_KEYWORDS_ARRAY.filter { it !in knownModifiers }.forEach {
+ KtTokens.MODIFIER_KEYWORDS_ARRAY.filter {
+ it !in knownModifiers
+ }.sortedBy {
+ MODIFIERS_ORDER.indexOf(it)
+ }.forEach {
if (psi.hasModifier(it)) {
appendTextNode(it.value, NodeKind.Modifier)
}
@@ -414,20 +467,49 @@ class DocumentationBuilder
if (options.skipEmptyPackages && declarations.none { it.isDocumented(options) }) continue
logger.info(" package $packageName: ${declarations.count()} declarations")
- val packageNode = findOrCreatePackageNode(packageName.asString(), packageContent, this@DocumentationBuilder.refGraph)
+ val packageNode = findOrCreatePackageNode(this, packageName.asString(), packageContent, this@DocumentationBuilder.refGraph)
packageDocumentationBuilder.buildPackageDocumentation(this@DocumentationBuilder, packageName, packageNode,
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 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 allExtensionFunctions = allDescriptors
+ 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 }
@@ -435,15 +517,31 @@ class DocumentationBuilder
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)
}
}
@@ -451,12 +549,9 @@ class DocumentationBuilder
}
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>> {
@@ -495,34 +590,60 @@ class DocumentationBuilder
}
fun DeclarationDescriptor.build(): DocumentationNode = when (this) {
- is ClassDescriptor -> build()
+ is ClassifierDescriptor -> build()
is ConstructorDescriptor -> build()
is PropertyDescriptor -> build()
is FunctionDescriptor -> build()
- is TypeParameterDescriptor -> build()
is ValueParameterDescriptor -> build()
is ReceiverParameterDescriptor -> build()
- is TypeAliasDescriptor -> build()
else -> throw IllegalStateException("Descriptor $this is not known")
}
- fun TypeAliasDescriptor.build(): DocumentationNode {
+ 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)
+ is TypeParameterDescriptor -> build()
+ else -> throw IllegalStateException("Descriptor $this is not known")
+ }
+
+ fun TypeAliasDescriptor.build(external: Boolean = false): DocumentationNode {
val node = nodeForDescriptor(this, NodeKind.TypeAlias)
- node.appendAnnotations(this)
+ if (!external) {
+ node.appendAnnotations(this)
+ }
node.appendModifiers(this)
node.appendInPageChildren(typeConstructor.parameters, RefKind.Detail)
node.appendType(underlyingType, NodeKind.TypeAliasUnderlyingType)
- node.appendSourceLink(source)
- node.appendDefaultPlatforms(this)
-
+ if (!external) {
+ node.appendSourceLink(source)
+ node.appendDefaultPlatforms(this)
+ }
register(this, node)
return node
}
- fun ClassDescriptor.build(): DocumentationNode {
+ fun ClassDescriptor.build(external: Boolean = false): DocumentationNode {
val kind = when {
kind == ClassKind.OBJECT -> NodeKind.Object
kind == ClassKind.INTERFACE -> NodeKind.Interface
@@ -532,21 +653,25 @@ class DocumentationBuilder
isSubclassOfThrowable() -> NodeKind.Exception
else -> NodeKind.Class
}
- val node = nodeForDescriptor(this, kind)
- typeConstructor.supertypes.forEach {
- node.appendSupertype(this, it)
+ val node = nodeForDescriptor(this, kind, external)
+ register(this, node)
+ supertypesWithAnyPrecise().forEach {
+ node.appendSupertype(this, it, !external)
}
if (getKind() != ClassKind.OBJECT && getKind() != ClassKind.ENUM_ENTRY) {
node.appendInPageChildren(typeConstructor.parameters, RefKind.Detail)
}
- for ((descriptor, inheritedLinkKind, extraModifier) in collectMembersToDocument()) {
- node.appendClassMember(descriptor, inheritedLinkKind, extraModifier)
+ if (!external) {
+ for ((descriptor, inheritedLinkKind, extraModifier) in collectMembersToDocument()) {
+ node.appendClassMember(descriptor, inheritedLinkKind, extraModifier)
+ }
+ node.appendAnnotations(this)
}
- node.appendAnnotations(this)
node.appendModifiers(this)
- node.appendSourceLink(source)
- node.appendDefaultPlatforms(this)
- register(this, node)
+ if (!external) {
+ node.appendSourceLink(source)
+ node.appendDefaultPlatforms(this)
+ }
return node
}
@@ -613,12 +738,12 @@ class DocumentationBuilder
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) }
@@ -626,8 +751,12 @@ class DocumentationBuilder
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)
@@ -648,32 +777,47 @@ class DocumentationBuilder
}
}
- 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")
+
+ if (isConst) {
+ this.compileTimeInitializer?.toDocumentationNode()?.let { node.append(it, RefKind.Detail) }
+ }
+
+
+ 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
@@ -775,8 +919,8 @@ class DocumentationBuilder
return node
}
- fun ConstantValue<*>.toDocumentationNode(): DocumentationNode? = value?.let { value ->
- when (value) {
+ fun ConstantValue<*>.toDocumentationNode(): DocumentationNode? = value.let { value ->
+ val text = when (value) {
is String ->
"\"" + StringUtil.escapeStringCharacters(value) + "\""
is EnumEntrySyntheticClassDescriptor ->
@@ -789,19 +933,40 @@ class DocumentationBuilder
value.toString()
}
}
- else -> value.toString()
- }.let { valueString ->
- DocumentationNode(valueString, Content.Empty, NodeKind.Value)
+ else -> "$value"
}
+ DocumentationNode(text, Content.Empty, NodeKind.Value)
+ }
+
+
+ fun DocumentationNode.getParentForPackageMember(descriptor: DeclarationDescriptor,
+ externalClassNodes: MutableMap<FqName, DocumentationNode>,
+ allFqNames: Collection<FqName>): DocumentationNode {
+ if (descriptor is CallableMemberDescriptor) {
+ val extensionClassDescriptor = descriptor.getExtensionClassDescriptor()
+ if (extensionClassDescriptor != null && isExtensionForExternalClass(descriptor, extensionClassDescriptor, allFqNames) &&
+ !ErrorUtils.isError(extensionClassDescriptor)) {
+ val fqName = DescriptorUtils.getFqNameSafe(extensionClassDescriptor)
+ return externalClassNodes.getOrPut(fqName, {
+ val newNode = DocumentationNode(fqName.asString(), Content.Empty, NodeKind.ExternalClass)
+ val externalLink = linkResolver.externalDocumentationLinkResolver.buildExternalDocumentationLink(extensionClassDescriptor)
+ if (externalLink != null) {
+ newNode.append(DocumentationNode(externalLink, Content.Empty, NodeKind.ExternalLink), RefKind.Link)
+ }
+ append(newNode, RefKind.Member)
+ newNode
+ })
+ }
+ }
+ return this
}
-}
-val visibleToDocumentation = setOf(Visibilities.PROTECTED, Visibilities.PUBLIC)
+}
fun DeclarationDescriptor.isDocumented(options: DocumentationOptions): Boolean {
return (options.effectivePackageOptions(fqNameSafe).includeNonPublic
|| this !is MemberDescriptor
- || this.visibility in visibleToDocumentation)
+ || this.visibility.isPublicAPI)
&& !isDocumentationSuppressed(options)
&& (!options.effectivePackageOptions(fqNameSafe).skipDeprecated || !isDeprecated())
}
@@ -833,16 +998,11 @@ class KotlinJavaDocumentationBuilder
val logger: DokkaLogger) : JavaDocumentationBuilder {
override fun appendFile(file: PsiJavaFile, module: DocumentationModule, packageContent: Map<String, Content>) {
val classDescriptors = file.classes.map {
- val javaDescriptorResolver = resolutionFacade.getFrontendService(JavaDescriptorResolver::class.java)
-
- javaDescriptorResolver.resolveClass(JavaClassImpl(it)) ?: run {
- logger.warn("Cannot find descriptor for Java class ${it.qualifiedName}")
- null
- }
+ it.getJavaClassDescriptor(resolutionFacade)
}
if (classDescriptors.any { it != null && it.isDocumented(options) }) {
- val packageNode = module.findOrCreatePackageNode(file.packageName, packageContent, documentationBuilder.refGraph)
+ val packageNode = findOrCreatePackageNode(module, file.packageName, packageContent, documentationBuilder.refGraph)
for (descriptor in classDescriptors.filterNotNull()) {
with(documentationBuilder) {
@@ -893,24 +1053,6 @@ 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>,
- allFqNames: Collection<FqName>): DocumentationNode {
- if (descriptor is CallableMemberDescriptor) {
- val extensionClassDescriptor = descriptor.getExtensionClassDescriptor()
- if (extensionClassDescriptor != null && isExtensionForExternalClass(descriptor, extensionClassDescriptor, allFqNames) &&
- !ErrorUtils.isError(extensionClassDescriptor)) {
- val fqName = DescriptorUtils.getFqNameSafe(extensionClassDescriptor)
- return externalClassNodes.getOrPut(fqName, {
- val newNode = DocumentationNode(fqName.asString(), Content.Empty, NodeKind.ExternalClass)
- append(newNode, RefKind.Member)
- newNode
- })
- }
- }
- return this
-}
-
fun CallableMemberDescriptor.getExtensionClassDescriptor(): ClassifierDescriptor? {
val extensionReceiver = extensionReceiverParameter
if (extensionReceiver != null) {
@@ -1004,7 +1146,7 @@ fun DocumentationModule.prepareForGeneration(options: DocumentationOptions) {
fun DocumentationNode.generateAllTypesNode() {
val allTypes = members(NodeKind.Package)
.flatMap { it.members.filter { it.kind in NodeKind.classLike || it.kind == NodeKind.ExternalClass } }
- .sortedBy { if (it.kind == NodeKind.ExternalClass) it.name.substringAfterLast('.') else it.name }
+ .sortedBy { if (it.kind == NodeKind.ExternalClass) it.name.substringAfterLast('.').toLowerCase() else it.name.toLowerCase() }
val allTypesNode = DocumentationNode("alltypes", Content.Empty, NodeKind.AllTypes)
for (typeNode in allTypes) {
@@ -1013,3 +1155,10 @@ fun DocumentationNode.generateAllTypesNode() {
append(allTypesNode, RefKind.Member)
}
+
+fun ClassDescriptor.supertypesWithAnyPrecise(): Collection<KotlinType> {
+ if (KotlinBuiltIns.isAny(this)) {
+ return emptyList()
+ }
+ return typeConstructor.supertypesWithAny()
+} \ No newline at end of file
diff --git a/core/src/main/kotlin/Kotlin/ExternalDocumentationLinkResolver.kt b/core/src/main/kotlin/Kotlin/ExternalDocumentationLinkResolver.kt
index e19ecf76..a8129793 100644
--- a/core/src/main/kotlin/Kotlin/ExternalDocumentationLinkResolver.kt
+++ b/core/src/main/kotlin/Kotlin/ExternalDocumentationLinkResolver.kt
@@ -2,14 +2,16 @@ package org.jetbrains.dokka
import com.google.inject.Inject
import com.google.inject.Singleton
+import com.intellij.psi.PsiElement
import com.intellij.psi.PsiMethod
import com.intellij.util.io.*
+import org.jetbrains.dokka.Formats.FileGeneratorBasedFormatDescriptor
+import org.jetbrains.dokka.Formats.FormatDescriptor
+import org.jetbrains.dokka.Utilities.ServiceLocator
+import org.jetbrains.dokka.Utilities.lookup
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.EnumEntrySyntheticClassDescriptor
-import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor
-import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
-import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor
-import org.jetbrains.kotlin.load.java.descriptors.JavaPropertyDescriptor
+import org.jetbrains.kotlin.load.java.descriptors.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
@@ -21,12 +23,15 @@ import java.net.URL
import java.net.URLConnection
import java.nio.file.Path
import java.security.MessageDigest
+import javax.inject.Named
+import kotlin.reflect.full.findAnnotation
fun ByteArray.toHexString() = this.joinToString(separator = "") { "%02x".format(it) }
@Singleton
class ExternalDocumentationLinkResolver @Inject constructor(
val options: DocumentationOptions,
+ @Named("libraryResolutionFacade") val libraryResolutionFacade: DokkaResolutionFacade,
val logger: DokkaLogger
) {
@@ -129,13 +134,22 @@ class ExternalDocumentationLinkResolver @Inject constructor(
.map { (key, value) -> key to value }
.toMap()
- val resolver = if (format == "javadoc") {
- InboundExternalLinkResolutionService.Javadoc()
- } else {
- val linkExtension = paramsMap["linkExtension"]?.singleOrNull() ?:
- throw RuntimeException("Failed to parse package list from $packageListUrl")
- InboundExternalLinkResolutionService.Dokka(linkExtension)
- }
+
+ val defaultResolverDesc = services["dokka-default"]!!
+ val resolverDesc = services[format]
+ ?: defaultResolverDesc.takeIf { format in formatsWithDefaultResolver }
+ ?: defaultResolverDesc.also {
+ logger.warn("Couldn't find InboundExternalLinkResolutionService(format = `$format`) for $link, using Dokka default")
+ }
+
+
+ val resolverClass = javaClass.classLoader.loadClass(resolverDesc.className).kotlin
+
+ val constructors = resolverClass.constructors
+
+ val constructor = constructors.singleOrNull()
+ ?: constructors.first { it.findAnnotation<Inject>() != null }
+ val resolver = constructor.call(paramsMap) as InboundExternalLinkResolutionService
val rootInfo = ExternalDocumentationRoot(link.url, resolver, locations)
@@ -152,11 +166,17 @@ class ExternalDocumentationLinkResolver @Inject constructor(
}
}
+ fun buildExternalDocumentationLink(element: PsiElement): String? {
+ return element.extractDescriptor(libraryResolutionFacade)?.let {
+ buildExternalDocumentationLink(it)
+ }
+ }
+
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
}
@@ -170,6 +190,15 @@ class ExternalDocumentationLinkResolver @Inject constructor(
companion object {
const val DOKKA_PARAM_PREFIX = "\$dokka."
+ val services = ServiceLocator.allServices("inbound-link-resolver").associateBy { it.name }
+ private val formatsWithDefaultResolver =
+ ServiceLocator
+ .allServices("format")
+ .filter {
+ val desc = ServiceLocator.lookup<FormatDescriptor>(it) as? FileGeneratorBasedFormatDescriptor
+ desc?.generatorServiceClass == FileGenerator::class
+ }.map { it.name }
+ .toSet()
}
}
@@ -177,7 +206,7 @@ class ExternalDocumentationLinkResolver @Inject constructor(
interface InboundExternalLinkResolutionService {
fun getPath(symbol: DeclarationDescriptor): String?
- class Javadoc : InboundExternalLinkResolutionService {
+ class Javadoc(paramsMap: Map<String, List<String>>) : InboundExternalLinkResolutionService {
override fun getPath(symbol: DeclarationDescriptor): String? {
if (symbol is EnumEntrySyntheticClassDescriptor) {
return getPath(symbol.containingDeclaration)?.let { it + "#" + symbol.name.asString() }
@@ -187,7 +216,7 @@ interface InboundExternalLinkResolutionService {
val containingClass = symbol.containingDeclaration as? JavaClassDescriptor ?: return null
val containingClassLink = getPath(containingClass)
if (containingClassLink != null) {
- if (symbol is JavaMethodDescriptor) {
+ if (symbol is JavaMethodDescriptor || symbol is JavaClassConstructorDescriptor) {
val psi = symbol.sourcePsi() as? PsiMethod
if (psi != null) {
val params = psi.parameterList.parameters.joinToString { it.type.canonicalText }
@@ -203,7 +232,9 @@ interface InboundExternalLinkResolutionService {
}
}
- class Dokka(val extension: String) : InboundExternalLinkResolutionService {
+ class Dokka(val paramsMap: Map<String, List<String>>) : InboundExternalLinkResolutionService {
+ val extension = paramsMap["linkExtension"]?.singleOrNull() ?: error("linkExtension not provided for Dokka resolver")
+
override fun getPath(symbol: DeclarationDescriptor): String? {
val leafElement = when (symbol) {
is CallableDescriptor, is TypeAliasDescriptor -> true
diff --git a/core/src/main/kotlin/Kotlin/KotlinAsJavaDescriptorSignatureProvider.kt b/core/src/main/kotlin/Kotlin/KotlinAsJavaDescriptorSignatureProvider.kt
deleted file mode 100644
index a3be658e..00000000
--- a/core/src/main/kotlin/Kotlin/KotlinAsJavaDescriptorSignatureProvider.kt
+++ /dev/null
@@ -1,22 +0,0 @@
-package org.jetbrains.dokka.Kotlin
-
-import org.jetbrains.dokka.Model.DescriptorSignatureProvider
-import org.jetbrains.dokka.getSignature
-import org.jetbrains.dokka.sourcePsi
-import org.jetbrains.kotlin.asJava.toLightElements
-import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
-import org.jetbrains.kotlin.psi.KtElement
-
-class KotlinAsJavaDescriptorSignatureProvider : DescriptorSignatureProvider {
- override fun signature(forDesc: DeclarationDescriptor): String {
- val sourcePsi = forDesc.sourcePsi()
- val javaLikePsi = if (sourcePsi is KtElement) {
- sourcePsi.toLightElements().firstOrNull()
- } else {
- sourcePsi
- }
-
- return getSignature(javaLikePsi) ?:
- "not implemented for $forDesc with psi: $sourcePsi"
- }
-} \ No newline at end of file
diff --git a/core/src/main/kotlin/Kotlin/KotlinAsJavaDocumentationBuilder.kt b/core/src/main/kotlin/Kotlin/KotlinAsJavaDocumentationBuilder.kt
index c7ed8292..00a795d0 100644
--- a/core/src/main/kotlin/Kotlin/KotlinAsJavaDocumentationBuilder.kt
+++ b/core/src/main/kotlin/Kotlin/KotlinAsJavaDocumentationBuilder.kt
@@ -6,9 +6,11 @@ import com.intellij.psi.PsiClass
import com.intellij.psi.PsiNamedElement
import org.jetbrains.dokka.Kotlin.DescriptorDocumentationParser
import org.jetbrains.kotlin.asJava.elements.KtLightElement
+import org.jetbrains.kotlin.asJava.elements.KtLightMethod
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.FqName
+import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.psi.KtPropertyAccessor
@@ -59,8 +61,9 @@ class KotlinAsJavaDocumentationParser
return JavadocParseResult.Empty
}
}
+ val isDefaultNoArgConstructor = kotlinLightElement is KtLightMethod && origin is KtClass
val descriptor = resolutionFacade.resolveToDescriptor(origin)
- val content = descriptorDocumentationParser.parseDocumentation(descriptor, origin is KtParameter)
+ val content = descriptorDocumentationParser.parseDocumentation(descriptor, origin is KtParameter, isDefaultNoArgConstructor)
return JavadocParseResult(content, null)
}
}
diff --git a/core/src/main/kotlin/Kotlin/KotlinAsJavaElementSignatureProvider.kt b/core/src/main/kotlin/Kotlin/KotlinAsJavaElementSignatureProvider.kt
new file mode 100644
index 00000000..20ea179e
--- /dev/null
+++ b/core/src/main/kotlin/Kotlin/KotlinAsJavaElementSignatureProvider.kt
@@ -0,0 +1,25 @@
+package org.jetbrains.dokka
+
+import com.intellij.psi.PsiElement
+import org.jetbrains.kotlin.asJava.toLightElements
+import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
+import org.jetbrains.kotlin.psi.KtElement
+
+class KotlinAsJavaElementSignatureProvider : ElementSignatureProvider {
+
+ private fun PsiElement.javaLikePsi() = when {
+ this is KtElement -> toLightElements().firstOrNull()
+ else -> this
+ }
+
+ override fun signature(forPsi: PsiElement): String {
+ return getSignature(forPsi.javaLikePsi()) ?:
+ "not implemented for $forPsi"
+ }
+
+ override fun signature(forDesc: DeclarationDescriptor): String {
+ val sourcePsi = forDesc.sourcePsi()
+ return getSignature(sourcePsi?.javaLikePsi()) ?:
+ "not implemented for $forDesc with psi: $sourcePsi"
+ }
+} \ No newline at end of file
diff --git a/core/src/main/kotlin/Kotlin/KotlinDescriptorSignatureProvider.kt b/core/src/main/kotlin/Kotlin/KotlinDescriptorSignatureProvider.kt
deleted file mode 100644
index 7ecd0389..00000000
--- a/core/src/main/kotlin/Kotlin/KotlinDescriptorSignatureProvider.kt
+++ /dev/null
@@ -1,9 +0,0 @@
-package org.jetbrains.dokka.Kotlin
-
-import org.jetbrains.dokka.Model.DescriptorSignatureProvider
-import org.jetbrains.dokka.signature
-import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
-
-class KotlinDescriptorSignatureProvider : DescriptorSignatureProvider {
- override fun signature(forDesc: DeclarationDescriptor): String = forDesc.signature()
-} \ No newline at end of file
diff --git a/core/src/main/kotlin/Kotlin/KotlinElementSignatureProvider.kt b/core/src/main/kotlin/Kotlin/KotlinElementSignatureProvider.kt
new file mode 100644
index 00000000..bcac0182
--- /dev/null
+++ b/core/src/main/kotlin/Kotlin/KotlinElementSignatureProvider.kt
@@ -0,0 +1,34 @@
+package org.jetbrains.dokka
+
+import com.intellij.psi.PsiElement
+import com.intellij.psi.PsiMember
+import com.intellij.psi.PsiPackage
+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? {
+ val forPsi = this
+
+ return when (forPsi) {
+ is KtLightElement<*, *> -> return (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
index f33c8c96..5f43c22e 100644
--- a/core/src/main/kotlin/Kotlin/KotlinLanguageService.kt
+++ b/core/src/main/kotlin/Kotlin/KotlinLanguageService.kt
@@ -5,8 +5,13 @@ import org.jetbrains.dokka.LanguageService.RenderMode
/**
* Implements [LanguageService] and provides rendering of symbols in Kotlin language
*/
-class KotlinLanguageService : LanguageService {
- private val fullOnlyModifiers = setOf("public", "protected", "private", "inline", "noinline", "crossinline", "reified")
+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 {
@@ -17,11 +22,12 @@ class KotlinLanguageService : LanguageService {
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(node)
+ NodeKind.Modifier -> renderModifier(this, node, renderMode)
NodeKind.Constructor,
NodeKind.Function,
NodeKind.CompanionObjectFunction -> renderFunction(node, renderMode)
@@ -32,12 +38,6 @@ class KotlinLanguageService : LanguageService {
}
}
- override fun renderName(node: DocumentationNode): String {
- return when (node.kind) {
- NodeKind.Constructor -> node.owner!!.name
- else -> node.name
- }
- }
override fun summarizeSignatures(nodes: List<DocumentationNode>): ContentNode? {
if (nodes.size < 2) return null
@@ -46,10 +46,17 @@ class KotlinLanguageService : LanguageService {
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))
+ renderFunction(
+ functionWithTypeParameter,
+ RenderMode.SUMMARY,
+ SummarizingMapper(receiverKind, typeParameter.name)
+ )
+ } else {
+ renderProperty(
+ functionWithTypeParameter,
+ RenderMode.SUMMARY,
+ SummarizingMapper(receiverKind, typeParameter.name)
+ )
}
}
}
@@ -70,26 +77,27 @@ class KotlinLanguageService : LanguageService {
companion object {
private val arrayClasses = setOf(
- "kotlin.Array",
- "kotlin.BooleanArray",
- "kotlin.ByteArray",
- "kotlin.CharArray",
- "kotlin.ShortArray",
- "kotlin.IntArray",
- "kotlin.LongArray",
- "kotlin.FloatArray",
- "kotlin.DoubleArray"
+ "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
+ "kotlin.Collection",
+ "kotlin.Sequence",
+ "kotlin.Iterable",
+ "kotlin.Map",
+ "kotlin.String",
+ "kotlin.CharSequence"
+ ) + arrayOrListClasses
}
private enum class ReceiverKind(val receiverName: String, val classes: Collection<String>) {
@@ -102,53 +110,21 @@ class KotlinLanguageService : LanguageService {
fun renderReceiver(receiver: DocumentationNode, to: ContentBlock)
}
- private class SummarizingMapper(val kind: ReceiverKind, val typeParameterName: String): SignatureMapper {
+ 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.renderPackage(node: DocumentationNode) {
- keyword("package")
- text(" ")
- identifier(node.name)
- }
-
- private fun <T> ContentBlock.renderList(nodes: List<T>, separator: String = ", ",
- noWrap: Boolean = false, renderItem: (T) -> Unit) {
- if (nodes.none())
- return
- renderItem(nodes.first())
- nodes.drop(1).forEach {
- if (noWrap) {
- symbol(separator.removeSuffix(" "))
- nbsp()
- } else {
- symbol(separator)
- }
- renderItem(it)
- }
- }
-
- private fun ContentBlock.renderLinked(node: DocumentationNode, body: ContentBlock.(DocumentationNode)->Unit) {
- val to = node.links.firstOrNull()
- if (to == null)
- body(node)
- else
- link(to) {
- body(node)
- }
- }
-
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()
- }
+ .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) {
@@ -190,15 +166,27 @@ class KotlinLanguageService : LanguageService {
keyword("dynamic")
return
}
+
+ val nullabilityModifier = node.detailOrNull(NodeKind.NullabilityModifier)
+
if (node.isFunctionalType()) {
- renderFunctionalType(node, renderMode)
+ 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(node) { identifier(it.name, IdentifierKind.TypeName) }
+ renderLinked(this, node) {
+ identifier(it.typeDeclarationClass?.classNodeNameWithOuterClass() ?: it.name, IdentifierKind.TypeName)
+ }
val typeArguments = node.details(NodeKind.Type)
if (typeArguments.isNotEmpty()) {
symbol("<")
@@ -207,22 +195,24 @@ class KotlinLanguageService : LanguageService {
}
symbol(">")
}
- val nullabilityModifier = node.details(NodeKind.NullabilityModifier).singleOrNull()
- if (nullabilityModifier != null) {
+
+ nullabilityModifier ?.apply {
symbol(nullabilityModifier.name)
}
}
- private fun ContentBlock.renderModifier(node: DocumentationNode, nowrap: Boolean = false) {
+ override fun renderModifier(
+ block: ContentBlock,
+ node: DocumentationNode,
+ renderMode: RenderMode,
+ nowrap: Boolean
+ ) {
when (node.name) {
- "final", "public", "var" -> {}
+ "final", "public", "var" -> {
+ }
else -> {
- keyword(node.name)
- if (nowrap) {
- nbsp()
- }
- else {
- text(" ")
+ if (showModifierInSummary(node) || renderMode == RenderMode.FULL) {
+ super.renderModifier(block, node, renderMode, nowrap)
}
}
}
@@ -238,11 +228,12 @@ class KotlinLanguageService : LanguageService {
nbsp()
symbol(":")
nbsp()
- renderList(constraints, noWrap=true) {
+ renderList(constraints, noWrap = true) {
renderType(it, renderMode)
}
}
}
+
private fun ContentBlock.renderParameter(node: DocumentationNode, renderMode: RenderMode) {
if (renderMode == RenderMode.FULL) {
renderAnnotationsForNode(node)
@@ -274,9 +265,12 @@ class KotlinLanguageService : LanguageService {
}
private fun ContentBlock.renderExtraTypeParameterConstraints(node: DocumentationNode, renderMode: RenderMode) {
- val parametersWithMultipleConstraints = node.details(NodeKind.TypeParameter).filter { it.details(NodeKind.UpperBound).size > 1 }
+ 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 } }
+ .flatMap { parameter ->
+ parameter.details(NodeKind.UpperBound).map { constraint -> parameter to constraint }
+ }
if (parametersWithMultipleConstraints.isNotEmpty()) {
keyword(" where ")
renderList(parametersWithConstraints) {
@@ -290,7 +284,7 @@ class KotlinLanguageService : LanguageService {
}
private fun ContentBlock.renderSupertypesForNode(node: DocumentationNode, renderMode: RenderMode) {
- val supertypes = node.details(NodeKind.Supertype)
+ val supertypes = node.details(NodeKind.Supertype).filterNot { it.qualifiedNameFromType() in ignoredSupertypes }
if (supertypes.any()) {
nbsp()
symbol(":")
@@ -302,20 +296,6 @@ class KotlinLanguageService : LanguageService {
}
}
- private fun ContentBlock.renderModifiersForNode(node: DocumentationNode,
- renderMode: RenderMode,
- nowrap: Boolean = false) {
- val modifiers = node.details(NodeKind.Modifier)
- for (it in modifiers) {
- if (node.kind == org.jetbrains.dokka.NodeKind.Interface && it.name == "abstract")
- continue
- if (renderMode == RenderMode.SUMMARY && it.name in fullOnlyModifiers) {
- continue
- }
- renderModifier(it, nowrap)
- }
- }
-
private fun ContentBlock.renderAnnotationsForNode(node: DocumentationNode) {
node.annotations.forEach {
renderAnnotation(it)
@@ -365,9 +345,11 @@ class KotlinLanguageService : LanguageService {
}
}
- private fun ContentBlock.renderFunction(node: DocumentationNode,
- renderMode: RenderMode,
- signatureMapper: SignatureMapper? = null) {
+ private fun ContentBlock.renderFunction(
+ node: DocumentationNode,
+ renderMode: RenderMode,
+ signatureMapper: SignatureMapper? = null
+ ) {
if (renderMode == RenderMode.FULL) {
renderAnnotationsForNode(node)
}
@@ -385,7 +367,7 @@ class KotlinLanguageService : LanguageService {
renderReceiver(node, renderMode, signatureMapper)
- if (node.kind != org.jetbrains.dokka.NodeKind.Constructor)
+ if (node.kind != NodeKind.Constructor)
identifierOrDeprecated(node)
symbol("(")
@@ -401,14 +383,17 @@ class KotlinLanguageService : LanguageService {
symbol(")")
symbol(": ")
renderType(node.detail(NodeKind.Type), renderMode)
- }
- else {
+ } else {
symbol(")")
}
renderExtraTypeParameterConstraints(node, renderMode)
}
- private fun ContentBlock.renderReceiver(node: DocumentationNode, renderMode: RenderMode, signatureMapper: SignatureMapper?) {
+ private fun ContentBlock.renderReceiver(
+ node: DocumentationNode,
+ renderMode: RenderMode,
+ signatureMapper: SignatureMapper?
+ ) {
val receiver = node.details(NodeKind.Receiver).singleOrNull()
if (receiver != null) {
if (signatureMapper != null) {
@@ -428,17 +413,19 @@ class KotlinLanguageService : LanguageService {
}
}
- private fun needReturnType(node: DocumentationNode) = when(node.kind) {
+ 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"
+ detail(NodeKind.Type).hiddenLinks.firstOrNull()?.qualifiedName() == "kotlin.Unit"
- private fun ContentBlock.renderProperty(node: DocumentationNode,
- renderMode: RenderMode,
- signatureMapper: SignatureMapper? = null) {
+ private fun ContentBlock.renderProperty(
+ node: DocumentationNode,
+ renderMode: RenderMode,
+ signatureMapper: SignatureMapper? = null
+ ) {
if (renderMode == RenderMode.FULL) {
renderAnnotationsForNode(node)
}
@@ -462,7 +449,7 @@ class KotlinLanguageService : LanguageService {
}
fun DocumentationNode.getPropertyKeyword() =
- if (details(NodeKind.Modifier).any { it.name == "var" }) "var" else "val"
+ if (details(NodeKind.Modifier).any { it.name == "var" }) "var" else "val"
fun ContentBlock.identifierOrDeprecated(node: DocumentationNode) {
if (node.deprecation != null) {
@@ -475,4 +462,12 @@ class KotlinLanguageService : LanguageService {
}
}
-fun DocumentationNode.qualifiedNameFromType() = (links.firstOrNull() ?: hiddenLinks.firstOrNull())?.qualifiedName() ?: 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)