• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.jetbrains.dokka.Formats
2 
3 import com.intellij.psi.PsiMember
4 import com.intellij.psi.PsiParameter
5 import org.jetbrains.dokka.*
6 import org.jetbrains.dokka.ExternalDocumentationLinkResolver.Companion.DOKKA_PARAM_PREFIX
7 import org.jetbrains.kotlin.asJava.toLightElements
8 import org.jetbrains.kotlin.descriptors.*
9 import org.jetbrains.kotlin.descriptors.impl.EnumEntrySyntheticClassDescriptor
10 import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor
11 import org.jetbrains.kotlin.load.java.descriptors.JavaPropertyDescriptor
12 import org.jetbrains.kotlin.psi.KtDeclaration
13 import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
14 import org.jetbrains.kotlin.resolve.descriptorUtil.isCompanionObject
15 import org.jetbrains.kotlin.types.KotlinType
16 
17 class JavaLayoutHtmlPackageListService: PackageListService {
18 
StringBuildernull19     private fun StringBuilder.appendParam(name: String, value: String) {
20         append(DOKKA_PARAM_PREFIX)
21         append(name)
22         append(":")
23         appendln(value)
24     }
25 
formatPackageListnull26     override fun formatPackageList(module: DocumentationModule): String {
27         val packages = module.members(NodeKind.Package).map { it.name }
28 
29         return buildString {
30             appendParam("format", "java-layout-html")
31             appendParam("mode", "kotlin")
32             for (p in packages) {
33                 appendln(p)
34             }
35         }
36     }
37 
38 }
39 
40 class JavaLayoutHtmlInboundLinkResolutionService(private val paramMap: Map<String, List<String>>,
41                                                  private val resolutionFacade: DokkaResolutionFacade) : InboundExternalLinkResolutionService {
42 
43     constructor(asJava: Boolean, resolutionFacade: DokkaResolutionFacade) :
44             this(mapOf("mode" to listOf(if (asJava) "java" else "kotlin")), resolutionFacade)
45 
46 
47     private val isJavaMode = paramMap["mode"]!!.single() == "java"
48 
getContainerPathnull49     private fun getContainerPath(symbol: DeclarationDescriptor): String? {
50         return when (symbol) {
51             is PackageFragmentDescriptor -> symbol.fqName.asString().replace('.', '/') + "/"
52             is ClassifierDescriptor -> getContainerPath(symbol.findPackage()) + symbol.nameWithOuter() + ".html"
53             else -> null
54         }
55     }
56 
findPackagenull57     private fun DeclarationDescriptor.findPackage(): PackageFragmentDescriptor =
58         generateSequence(this) { it.containingDeclaration }.filterIsInstance<PackageFragmentDescriptor>().first()
59 
nameWithOuternull60     private fun ClassifierDescriptor.nameWithOuter(): String =
61         generateSequence(this) { it.containingDeclaration as? ClassifierDescriptor }
<lambda>null62             .toList().asReversed().joinToString(".") { it.name.asString() }
63 
getJavaPagePathnull64     private fun getJavaPagePath(symbol: DeclarationDescriptor): String? {
65 
66         val sourcePsi = symbol.sourcePsi() ?: return null
67         val source = (if (sourcePsi is KtDeclaration) {
68             sourcePsi.toLightElements().firstOrNull()
69         } else {
70             sourcePsi
71         }) as? PsiMember ?: return null
72         val desc = source.getJavaMemberDescriptor(resolutionFacade) ?: return null
73         return getPagePath(desc)
74     }
75 
getPagePathnull76     private fun getPagePath(symbol: DeclarationDescriptor): String? {
77         return when (symbol) {
78             is PackageFragmentDescriptor -> getContainerPath(symbol) + "package-summary.html"
79             is EnumEntrySyntheticClassDescriptor -> getContainerPath(symbol.containingDeclaration) + "#" + symbol.signatureForAnchorUrlEncoded()
80             is ClassifierDescriptor -> getContainerPath(symbol) + "#"
81             is FunctionDescriptor, is PropertyDescriptor -> getContainerPath(symbol.containingDeclaration!!) + "#" + symbol.signatureForAnchorUrlEncoded()
82             else -> null
83         }
84     }
85 
DeclarationDescriptornull86     private fun DeclarationDescriptor.signatureForAnchor(): String? {
87 
88         fun ReceiverParameterDescriptor.extractReceiverName(): String {
89             var receiverClass: DeclarationDescriptor = type.constructor.declarationDescriptor!!
90             if (receiverClass.isCompanionObject()) {
91                 receiverClass = receiverClass.containingDeclaration!!
92             } else if (receiverClass is TypeParameterDescriptor) {
93                 val upperBoundClass = receiverClass.upperBounds.singleOrNull()?.constructor?.declarationDescriptor
94                 if (upperBoundClass != null) {
95                     receiverClass = upperBoundClass
96                 }
97             }
98 
99             return receiverClass.name.asString()
100         }
101 
102         fun KotlinType.qualifiedNameForSignature(): String {
103             val desc = constructor.declarationDescriptor
104             return desc?.fqNameUnsafe?.asString() ?: "<ERROR TYPE NAME>"
105         }
106 
107         fun StringBuilder.appendReceiverAndCompanion(desc: CallableDescriptor) {
108             if (desc.containingDeclaration.isCompanionObject()) {
109                 append("Companion.")
110             }
111             desc.extensionReceiverParameter?.let {
112                 append("(")
113                 append(it.extractReceiverName())
114                 append(").")
115             }
116         }
117 
118         return when (this) {
119             is EnumEntrySyntheticClassDescriptor -> buildString {
120                 append("ENUM_VALUE:")
121                 append(name.asString())
122             }
123             is JavaMethodDescriptor -> buildString {
124                 append(name.asString())
125                 valueParameters.joinTo(this, prefix = "(", postfix = ")") {
126                     val param = it.sourcePsi() as PsiParameter
127                     param.type.canonicalText
128                 }
129             }
130             is JavaPropertyDescriptor -> buildString {
131                 append(name.asString())
132             }
133             is FunctionDescriptor -> buildString {
134                 appendReceiverAndCompanion(this@signatureForAnchor)
135                 append(name.asString())
136                 valueParameters.joinTo(this, prefix = "(", postfix = ")") {
137                     it.type.qualifiedNameForSignature()
138                 }
139             }
140             is PropertyDescriptor -> buildString {
141                 appendReceiverAndCompanion(this@signatureForAnchor)
142                 append(name.asString())
143                 append(":")
144 
145                 append(returnType?.qualifiedNameForSignature())
146             }
147             else -> null
148         }
149     }
150 
DeclarationDescriptornull151     private fun DeclarationDescriptor.signatureForAnchorUrlEncoded(): String? = signatureForAnchor()?.anchorEncoded()
152 
153     override fun getPath(symbol: DeclarationDescriptor) = if (isJavaMode) getJavaPagePath(symbol) else getPagePath(symbol)
154 }
155