aboutsummaryrefslogtreecommitdiff
path: root/core/src/main/kotlin/Kotlin
diff options
context:
space:
mode:
Diffstat (limited to 'core/src/main/kotlin/Kotlin')
-rw-r--r--core/src/main/kotlin/Kotlin/ContentBuilder.kt9
-rw-r--r--core/src/main/kotlin/Kotlin/DeclarationLinkResolver.kt22
-rw-r--r--core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt2
-rw-r--r--core/src/main/kotlin/Kotlin/DocumentationBuilder.kt59
-rw-r--r--core/src/main/kotlin/Kotlin/ExternalDocumentationLinkResolver.kt42
-rw-r--r--core/src/main/kotlin/Kotlin/KotlinAsJavaDescriptorSignatureProvider.kt22
-rw-r--r--core/src/main/kotlin/Kotlin/KotlinDescriptorSignatureProvider.kt9
7 files changed, 137 insertions, 28 deletions
diff --git a/core/src/main/kotlin/Kotlin/ContentBuilder.kt b/core/src/main/kotlin/Kotlin/ContentBuilder.kt
index 771bc44b..c60625a4 100644
--- a/core/src/main/kotlin/Kotlin/ContentBuilder.kt
+++ b/core/src/main/kotlin/Kotlin/ContentBuilder.kt
@@ -110,9 +110,12 @@ fun buildContentTo(tree: MarkdownNode, target: ContentBlock, linkResolver: LinkR
}
MarkdownTokenTypes.CODE_LINE -> {
- val block = ContentBlockCode()
- block.append(ContentText(node.text))
- parent.append(block)
+ val content = ContentText(node.text)
+ if (parent is ContentBlockCode) {
+ parent.append(content)
+ } else {
+ parent.append(ContentBlockCode().apply { append(content) })
+ }
}
MarkdownTokenTypes.TEXT -> {
diff --git a/core/src/main/kotlin/Kotlin/DeclarationLinkResolver.kt b/core/src/main/kotlin/Kotlin/DeclarationLinkResolver.kt
index 2b085769..ffef399d 100644
--- a/core/src/main/kotlin/Kotlin/DeclarationLinkResolver.kt
+++ b/core/src/main/kotlin/Kotlin/DeclarationLinkResolver.kt
@@ -1,16 +1,21 @@
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,
val refGraph: NodeReferenceGraph,
val logger: DokkaLogger,
val options: DocumentationOptions,
- val externalDocumentationLinkResolver: ExternalDocumentationLinkResolver) {
+ val externalDocumentationLinkResolver: ExternalDocumentationLinkResolver,
+ val descriptorSignatureProvider: DescriptorSignatureProvider) {
fun tryResolveContentLink(fromDescriptor: DeclarationDescriptor, href: String): ContentBlock? {
@@ -29,7 +34,17 @@ class DeclarationLinkResolver
if (externalHref != null) {
return ContentExternalLink(externalHref)
}
- return ContentNodeLazyLink(href, { -> refGraph.lookupOrWarn(symbol.signature(), logger) })
+ val signature = descriptorSignatureProvider.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")
+ }
+ target
+ })
}
if ("/" in href) {
return ContentExternalLink(href)
@@ -51,6 +66,9 @@ class DeclarationLinkResolver
if (symbol is CallableMemberDescriptor && symbol.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
return symbol.overriddenDescriptors.firstOrNull()
}
+ if (symbol is TypeAliasDescriptor && !symbol.isDocumented(options)) {
+ return symbol.classDescriptor
+ }
return symbol
}
diff --git a/core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt b/core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt
index eb8c12d0..f2d9d3a7 100644
--- a/core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt
+++ b/core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt
@@ -81,7 +81,7 @@ class DescriptorDocumentationParser
val suppressAnnotation = annotations.findAnnotation(FqName(Suppress::class.qualifiedName!!))
return if (suppressAnnotation != null) {
@Suppress("UNCHECKED_CAST")
- (suppressAnnotation.argumentValue("names") as List<StringValue>).any { it.value == "NOT_DOCUMENTED" }
+ (suppressAnnotation.argumentValue("names")?.value as List<StringValue>).any { it.value == "NOT_DOCUMENTED" }
} else containingDeclaration?.isSuppressWarning() ?: false
}
diff --git a/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt b/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt
index fddf0814..916f89c9 100644
--- a/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt
+++ b/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt
@@ -15,14 +15,14 @@ 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.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.constants.ConstantValue
-import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
-import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
-import org.jetbrains.kotlin.resolve.descriptorUtil.isDocumentedAnnotation
+import org.jetbrains.kotlin.resolve.descriptorUtil.*
import org.jetbrains.kotlin.resolve.findTopMostOverriddenDescriptors
import org.jetbrains.kotlin.resolve.jvm.JavaDescriptorResolver
import org.jetbrains.kotlin.resolve.source.PsiSourceElement
@@ -50,6 +50,8 @@ class DocumentationOptions(val outputDir: String,
perPackageOptions: List<PackageOptions> = emptyList(),
externalDocumentationLinks: List<ExternalDocumentationLink> = emptyList(),
noStdlibLink: Boolean,
+ val languageVersion: String?,
+ val apiVersion: String?,
cacheRoot: String? = null,
val suppressedFiles: List<File> = emptyList()) {
init {
@@ -576,6 +578,11 @@ class DocumentationBuilder
descriptorsToDocument.mapTo(result) {
ClassMember(it, inheritedLinkKind = RefKind.InheritedCompanionObjectMember)
}
+
+ if (companionObjectDescriptor.getAllSuperclassesWithoutAny().isNotEmpty()
+ || companionObjectDescriptor.getSuperInterfaces().isNotEmpty()) {
+ result += ClassMember(companionObjectDescriptor)
+ }
}
return result
}
@@ -726,6 +733,7 @@ class DocumentationBuilder
}
node.appendType(constraint, NodeKind.UpperBound)
}
+ register(this, node)
return node
}
@@ -746,6 +754,7 @@ class DocumentationBuilder
val node = DocumentationNode(name.asString(), Content.Empty, NodeKind.Receiver)
node.appendType(type)
+ register(this, node)
return node
}
@@ -772,6 +781,14 @@ class DocumentationBuilder
"\"" + StringUtil.escapeStringCharacters(value) + "\""
is EnumEntrySyntheticClassDescriptor ->
value.containingDeclaration.name.asString() + "." + value.name.asString()
+ is Pair<*, *> -> {
+ val (classId, name) = value
+ if (classId is ClassId && name is Name) {
+ classId.shortClassName.asString() + "." + name.asString()
+ } else {
+ value.toString()
+ }
+ }
else -> value.toString()
}.let { valueString ->
DocumentationNode(valueString, Content.Empty, NodeKind.Value)
@@ -784,9 +801,9 @@ 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) &&
- !isDocumentationSuppressed(options) &&
- (!options.effectivePackageOptions(fqNameSafe).skipDeprecated || !isDeprecated())
+ || this.visibility in visibleToDocumentation)
+ && !isDocumentationSuppressed(options)
+ && (!options.effectivePackageOptions(fqNameSafe).skipDeprecated || !isDeprecated())
}
private fun DeclarationDescriptor.isGenerated() = this is CallableMemberDescriptor && kind != CallableMemberDescriptor.Kind.DECLARATION
@@ -856,6 +873,8 @@ fun AnnotationDescriptor.mustBeDocumented(): Boolean {
fun DeclarationDescriptor.isDocumentationSuppressed(options: DocumentationOptions): Boolean {
+ if (options.effectivePackageOptions(fqNameSafe).suppress) return true
+
val path = this.findPsi()?.containingFile?.virtualFile?.path
if (path != null) {
if (File(path).absoluteFile in options.suppressedFiles) return true
@@ -905,17 +924,21 @@ fun CallableMemberDescriptor.getExtensionClassDescriptor(): ClassifierDescriptor
return null
}
-fun DeclarationDescriptor.signature(): String = 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
- else -> throw UnsupportedOperationException("Don't know how to calculate signature for $this")
+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 {
@@ -932,7 +955,7 @@ fun CallableMemberDescriptor.parameterSignature(): String {
if (extensionReceiver != null) {
params.add(0, extensionReceiver.type)
}
- return "(" + params.map { it.signature() }.joinToString() + ")"
+ return params.joinToString(prefix = "(", postfix = ")") { it.signature() }
}
fun KotlinType.signature(): String {
diff --git a/core/src/main/kotlin/Kotlin/ExternalDocumentationLinkResolver.kt b/core/src/main/kotlin/Kotlin/ExternalDocumentationLinkResolver.kt
index 84d83c73..108cee78 100644
--- a/core/src/main/kotlin/Kotlin/ExternalDocumentationLinkResolver.kt
+++ b/core/src/main/kotlin/Kotlin/ExternalDocumentationLinkResolver.kt
@@ -15,7 +15,9 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.parents
import java.io.ByteArrayOutputStream
import java.io.PrintWriter
+import java.net.HttpURLConnection
import java.net.URL
+import java.net.URLConnection
import java.nio.file.Path
import java.security.MessageDigest
@@ -30,12 +32,44 @@ class ExternalDocumentationLinkResolver @Inject constructor(
val packageFqNameToLocation = mutableMapOf<FqName, ExternalDocumentationRoot>()
val formats = mutableMapOf<String, InboundExternalLinkResolutionService>()
- class ExternalDocumentationRoot(val rootUrl: URL, val resolver: InboundExternalLinkResolutionService, val locations: Map<String, String>)
+ class ExternalDocumentationRoot(val rootUrl: URL, val resolver: InboundExternalLinkResolutionService, val locations: Map<String, String>) {
+ override fun toString(): String = rootUrl.toString()
+ }
val cacheDir: Path? = options.cacheRoot?.resolve("packageListCache")?.apply { createDirectories() }
val cachedProtocols = setOf("http", "https", "ftp")
+ fun URL.doOpenConnectionToReadContent(timeout: Int = 10000, redirectsAllowed: Int = 16): URLConnection {
+ val connection = this.openConnection()
+ connection.connectTimeout = timeout
+ connection.readTimeout = timeout
+
+ when (connection) {
+ is HttpURLConnection -> {
+ return when (connection.responseCode) {
+ in 200..299 -> {
+ connection
+ }
+ HttpURLConnection.HTTP_MOVED_PERM,
+ HttpURLConnection.HTTP_MOVED_TEMP,
+ HttpURLConnection.HTTP_SEE_OTHER -> {
+ if (redirectsAllowed > 0) {
+ val newUrl = connection.getHeaderField("Location")
+ URL(newUrl).doOpenConnectionToReadContent(timeout, redirectsAllowed - 1)
+ } else {
+ throw RuntimeException("Too many redirects")
+ }
+ }
+ else -> {
+ throw RuntimeException("Unhandled http code: ${connection.responseCode}")
+ }
+ }
+ }
+ else -> return connection
+ }
+ }
+
fun loadPackageList(link: DokkaConfiguration.ExternalDocumentationLink) {
val packageListUrl = link.packageListUrl
@@ -50,7 +84,7 @@ class ExternalDocumentationLinkResolver @Inject constructor(
if (cacheEntry.exists()) {
try {
- val connection = packageListUrl.openConnection()
+ val connection = packageListUrl.doOpenConnectionToReadContent()
val originModifiedDate = connection.date
val cacheDate = cacheEntry.lastModified().toMillis()
if (originModifiedDate > cacheDate || originModifiedDate == 0L) {
@@ -60,7 +94,7 @@ class ExternalDocumentationLinkResolver @Inject constructor(
logger.info("Renewing package-list from $packageListUrl")
connection.getInputStream().copyTo(cacheEntry.outputStream())
}
- } catch(e: Exception) {
+ } catch (e: Exception) {
logger.error("Failed to update package-list cache for $link")
val baos = ByteArrayOutputStream()
PrintWriter(baos).use {
@@ -75,7 +109,7 @@ class ExternalDocumentationLinkResolver @Inject constructor(
}
cacheEntry.inputStream()
} else {
- packageListUrl.openStream()
+ packageListUrl.doOpenConnectionToReadContent().getInputStream()
}
val (params, packages) =
diff --git a/core/src/main/kotlin/Kotlin/KotlinAsJavaDescriptorSignatureProvider.kt b/core/src/main/kotlin/Kotlin/KotlinAsJavaDescriptorSignatureProvider.kt
new file mode 100644
index 00000000..a3be658e
--- /dev/null
+++ b/core/src/main/kotlin/Kotlin/KotlinAsJavaDescriptorSignatureProvider.kt
@@ -0,0 +1,22 @@
+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/KotlinDescriptorSignatureProvider.kt b/core/src/main/kotlin/Kotlin/KotlinDescriptorSignatureProvider.kt
new file mode 100644
index 00000000..7ecd0389
--- /dev/null
+++ b/core/src/main/kotlin/Kotlin/KotlinDescriptorSignatureProvider.kt
@@ -0,0 +1,9 @@
+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