aboutsummaryrefslogtreecommitdiff
path: root/src/Kotlin/DocumentationBuilder.kt
diff options
context:
space:
mode:
Diffstat (limited to 'src/Kotlin/DocumentationBuilder.kt')
-rw-r--r--src/Kotlin/DocumentationBuilder.kt209
1 files changed, 105 insertions, 104 deletions
diff --git a/src/Kotlin/DocumentationBuilder.kt b/src/Kotlin/DocumentationBuilder.kt
index 6bfeb360..2d3105ac 100644
--- a/src/Kotlin/DocumentationBuilder.kt
+++ b/src/Kotlin/DocumentationBuilder.kt
@@ -8,23 +8,28 @@ import org.jetbrains.kotlin.descriptors.*
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.caches.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.kdoc.KDocFinder
import org.jetbrains.kotlin.idea.kdoc.resolveKDocLink
+import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
+import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.kdoc.psi.impl.KDocSection
import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag
-import org.jetbrains.kotlin.lexer.JetSingleValueToken
+import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.FqName
-import org.jetbrains.kotlin.psi.JetParameter
+import org.jetbrains.kotlin.psi.KtModifierListOwner
+import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.resolve.DescriptorUtils
+import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant
import org.jetbrains.kotlin.resolve.constants.ConstantValue
+import org.jetbrains.kotlin.resolve.constants.TypedCompileTimeConstant
+import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
+import org.jetbrains.kotlin.resolve.descriptorUtil.isDocumentedAnnotation
import org.jetbrains.kotlin.resolve.lazy.ResolveSession
import org.jetbrains.kotlin.resolve.source.PsiSourceElement
import org.jetbrains.kotlin.resolve.source.getPsi
import org.jetbrains.kotlin.types.ErrorUtils
-import org.jetbrains.kotlin.types.JetType
+import org.jetbrains.kotlin.types.KtType
import org.jetbrains.kotlin.types.TypeProjection
-import org.jetbrains.kotlin.types.expressions.OperatorConventions
public data class DocumentationOptions(val includeNonPublic: Boolean = false,
val reportUndocumented: Boolean = true,
@@ -33,8 +38,8 @@ public data class DocumentationOptions(val includeNonPublic: Boolean = false,
val sourceLinks: List<SourceLinkDefinition>)
private fun isSamePackage(descriptor1: DeclarationDescriptor, descriptor2: DeclarationDescriptor): Boolean {
- val package1 = DescriptorUtils.getParentOfType(descriptor1, javaClass<PackageFragmentDescriptor>())
- val package2 = DescriptorUtils.getParentOfType(descriptor2, javaClass<PackageFragmentDescriptor>())
+ val package1 = DescriptorUtils.getParentOfType(descriptor1, PackageFragmentDescriptor::class.java)
+ val package2 = DescriptorUtils.getParentOfType(descriptor2, PackageFragmentDescriptor::class.java)
return package1 != null && package2 != null && package1.fqName == package2.fqName
}
@@ -47,6 +52,10 @@ class DocumentationBuilder(val resolutionFacade: ResolutionFacade,
val boringBuiltinClasses = setOf(
"kotlin.Unit", "kotlin.Byte", "kotlin.Short", "kotlin.Int", "kotlin.Long", "kotlin.Char", "kotlin.Boolean",
"kotlin.Float", "kotlin.Double", "kotlin.String", "kotlin.Array", "kotlin.Any")
+ val knownModifiers = setOf(
+ KtTokens.PUBLIC_KEYWORD, KtTokens.PROTECTED_KEYWORD, KtTokens.INTERNAL_KEYWORD, KtTokens.PRIVATE_KEYWORD,
+ KtTokens.OPEN_KEYWORD, KtTokens.FINAL_KEYWORD, KtTokens.ABSTRACT_KEYWORD, KtTokens.SEALED_KEYWORD,
+ KtTokens.OVERRIDE_KEYWORD)
fun parseDocumentation(descriptor: DeclarationDescriptor): Content {
val kdoc = KDocFinder.findKDoc(descriptor) ?: findStdlibKDoc(descriptor)
@@ -101,9 +110,10 @@ class DocumentationBuilder(val resolutionFacade: ResolutionFacade,
deepestDescriptor = deepestDescriptor.overriddenDescriptors.first()
}
if (DescriptorUtils.getFqName(deepestDescriptor.containingDeclaration).asString() == "kotlin.Any") {
- val anyClassDescriptors = session.getTopLevelClassDescriptors(FqName.fromSegments(listOf("kotlin", "Any")))
+ val anyClassDescriptors = session.getTopLevelClassDescriptors(FqName.fromSegments(listOf("kotlin", "Any")),
+ NoLookupLocation.UNSORTED)
anyClassDescriptors.forEach {
- val anyMethod = it.getMemberScope(listOf()).getFunctions(descriptor.name).single()
+ val anyMethod = it.getMemberScope(listOf()).getFunctions(descriptor.name, NoLookupLocation.UNSORTED).single()
val kdoc = KDocFinder.findKDoc(anyMethod)
if (kdoc != null) {
return kdoc
@@ -115,7 +125,7 @@ class DocumentationBuilder(val resolutionFacade: ResolutionFacade,
}
fun DeclarationDescriptor.isDeprecated(): Boolean = annotations.any {
- DescriptorUtils.getFqName(it.type.constructor.declarationDescriptor!!).asString() == "kotlin.deprecated"
+ DescriptorUtils.getFqName(it.type.constructor.declarationDescriptor!!).asString() == "kotlin.Deprecated"
} || (this is ConstructorDescriptor && containingDeclaration.isDeprecated())
fun DeclarationDescriptor.signature(): String = when(this) {
@@ -142,13 +152,13 @@ class DocumentationBuilder(val resolutionFacade: ResolutionFacade,
if (extensionReceiver != null) {
params.add(0, extensionReceiver.type)
}
- return "(" + params.map { it.signature() }.join() + ")"
+ return "(" + params.map { it.signature() }.joinToString() + ")"
}
- fun JetType.signature(): String {
+ fun KtType.signature(): String {
val declarationDescriptor = constructor.declarationDescriptor ?: return "<null>"
val typeName = DescriptorUtils.getFqName(declarationDescriptor).asString()
- if (typeName == "Array" && arguments.size() == 1) {
+ if (typeName == "Array" && arguments.size == 1) {
return "Array<" + arguments.first().type.signature() + ">"
}
return typeName
@@ -203,12 +213,12 @@ class DocumentationBuilder(val resolutionFacade: ResolutionFacade,
return symbol
}
- fun KDocSection.getTags(): Array<KDocTag> = PsiTreeUtil.getChildrenOfType(this, javaClass<KDocTag>()) ?: arrayOf()
+ 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(ContentTags.SeeAlso) ?: addSection(ContentTags.SeeAlso, null)
+ val seeSection = findSectionByTag("See Also") ?: addSection("See Also", null)
val link = resolveContentLink(descriptor, subjectName)
link.append(ContentText(subjectName))
val para = ContentParagraph()
@@ -217,8 +227,8 @@ class DocumentationBuilder(val resolutionFacade: ResolutionFacade,
}
}
- fun link(node: DocumentationNode, descriptor: DeclarationDescriptor) {
- refGraph.link(node, descriptor.signature(), DocumentationReference.Kind.Link)
+ fun link(node: DocumentationNode, descriptor: DeclarationDescriptor, kind: DocumentationReference.Kind) {
+ refGraph.link(node, descriptor.signature(), kind)
}
fun link(fromDescriptor: DeclarationDescriptor?, toDescriptor: DeclarationDescriptor?, kind: DocumentationReference.Kind) {
@@ -231,7 +241,7 @@ class DocumentationBuilder(val resolutionFacade: ResolutionFacade,
refGraph.register(descriptor.signature(), node)
}
- fun DocumentationNode<T>(descriptor: T, kind: Kind): DocumentationNode where T : DeclarationDescriptor, T : Named {
+ fun <T> DocumentationNode(descriptor: T, kind: Kind): DocumentationNode where T : DeclarationDescriptor, T : Named {
val doc = parseDocumentation(descriptor)
val node = DocumentationNode(descriptor.name.asString(), doc, kind).withModifiers(descriptor)
return node
@@ -255,7 +265,7 @@ class DocumentationBuilder(val resolutionFacade: ResolutionFacade,
modality = Modality.FINAL
}
}
- val modifier = modality.name().toLowerCase()
+ val modifier = modality.name.toLowerCase()
appendTextNode(modifier, DocumentationNode.Kind.Modifier)
}
@@ -269,12 +279,14 @@ class DocumentationBuilder(val resolutionFacade: ResolutionFacade,
for (superType in superTypes) {
if (!ignoreSupertype(superType)) {
appendType(superType, DocumentationNode.Kind.Supertype)
- link(superType?.constructor?.declarationDescriptor, descriptor, DocumentationReference.Kind.Inheritor)
+ val superclass = superType?.constructor?.declarationDescriptor
+ link(superclass, descriptor, DocumentationReference.Kind.Inheritor)
+ link(descriptor, superclass, DocumentationReference.Kind.Superclass)
}
}
}
- private fun ignoreSupertype(superType: JetType): Boolean {
+ private fun ignoreSupertype(superType: KtType): Boolean {
val superClass = superType.constructor.declarationDescriptor as? ClassDescriptor
if (superClass != null) {
val fqName = DescriptorUtils.getFqNameSafe(superClass).asString()
@@ -284,10 +296,15 @@ class DocumentationBuilder(val resolutionFacade: ResolutionFacade,
}
fun DocumentationNode.appendProjection(projection: TypeProjection, kind: DocumentationNode.Kind = DocumentationNode.Kind.Type) {
- appendType(projection.type, kind, projection.projectionKind.label)
+ if (projection.isStarProjection) {
+ appendTextNode("*", Kind.Type)
+ }
+ else {
+ appendType(projection.type, kind, projection.projectionKind.label)
+ }
}
- fun DocumentationNode.appendType(jetType: JetType?, kind: DocumentationNode.Kind = DocumentationNode.Kind.Type, prefix: String = "") {
+ fun DocumentationNode.appendType(jetType: KtType?, kind: DocumentationNode.Kind = DocumentationNode.Kind.Type, prefix: String = "") {
if (jetType == null)
return
val classifierDescriptor = jetType.constructor.declarationDescriptor
@@ -311,28 +328,53 @@ class DocumentationBuilder(val resolutionFacade: ResolutionFacade,
if (jetType.isMarkedNullable) {
node.appendTextNode("?", Kind.NullabilityModifier)
}
- if (classifierDescriptor != null && !classifierDescriptor.isBoringBuiltinClass()) {
- link(node, classifierDescriptor)
+ if (classifierDescriptor != null) {
+ link(node, classifierDescriptor,
+ if (classifierDescriptor.isBoringBuiltinClass()) DocumentationReference.Kind.HiddenLink else DocumentationReference.Kind.Link)
}
append(node, DocumentationReference.Kind.Detail)
- for (typeArgument in jetType.arguments)
+ node.appendAnnotations(jetType)
+ for (typeArgument in jetType.arguments) {
node.appendProjection(typeArgument)
+ }
}
fun ClassifierDescriptor.isBoringBuiltinClass(): Boolean =
DescriptorUtils.getFqName(this).asString() in boringBuiltinClasses
fun DocumentationNode.appendAnnotations(annotated: Annotated) {
- annotated.annotations.forEach {
+ annotated.annotations.filter { it.isDocumented() }.forEach {
val annotationNode = it.build()
if (annotationNode != null) {
append(annotationNode,
- if (annotationNode.name == "deprecated") DocumentationReference.Kind.Deprecation else DocumentationReference.Kind.Annotation)
+ if (annotationNode.isDeprecation()) DocumentationReference.Kind.Deprecation else DocumentationReference.Kind.Annotation)
+ }
+ }
+ }
+
+ private fun AnnotationDescriptor.isDocumented(): Boolean {
+ if (source.getPsi() != null && mustBeDocumented()) return true
+ val annotationClassName = type.constructor.declarationDescriptor?.fqNameSafe?.asString()
+ return annotationClassName == "kotlin.Extension"
+ }
+
+ fun AnnotationDescriptor.mustBeDocumented(): Boolean {
+ val annotationClass = type.constructor.declarationDescriptor as? Annotated ?: return false
+ return annotationClass.isDocumentedAnnotation()
+ }
+
+ fun DocumentationNode.appendModifiers(descriptor: DeclarationDescriptor) {
+ val psi = (descriptor as DeclarationDescriptorWithSource).source.getPsi() as? KtModifierListOwner ?: return
+ KtTokens.MODIFIER_KEYWORDS_ARRAY.filter { it !in knownModifiers }.forEach {
+ if (psi.hasModifier(it)) {
+ appendTextNode(it.value, Kind.Modifier)
}
}
}
+ fun DocumentationNode.isDeprecation() = name == "Deprecated" || name == "deprecated"
+
fun DocumentationNode.appendSourceLink(sourceElement: SourceElement) {
appendSourceLink(sourceElement.getPsi(), options.sourceLinks)
}
@@ -364,8 +406,18 @@ class DocumentationBuilder(val resolutionFacade: ResolutionFacade,
}
- fun DocumentationNode.appendChildren(descriptors: Iterable<DeclarationDescriptor>, kind: DocumentationReference.Kind) {
- descriptors.forEach { descriptor -> appendChild(descriptor, kind) }
+ fun DocumentationNode.appendMembers(descriptors: Iterable<DeclarationDescriptor>) {
+ descriptors.forEach { descriptor ->
+ if (descriptor is CallableMemberDescriptor && descriptor.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
+ val baseDescriptor = descriptor.overriddenDescriptors.firstOrNull()
+ if (baseDescriptor != null) {
+ link(this, baseDescriptor, DocumentationReference.Kind.InheritedMember)
+ }
+ }
+ else {
+ appendChild(descriptor, DocumentationReference.Kind.Member)
+ }
+ }
}
fun DocumentationNode.appendInPageChildren(descriptors: Iterable<DeclarationDescriptor>, kind: DocumentationReference.Kind) {
@@ -381,7 +433,7 @@ class DocumentationBuilder(val resolutionFacade: ResolutionFacade,
val extensionClassDescriptor = descriptor.getExtensionClassDescriptor()
if (extensionClassDescriptor != null && !isSamePackage(descriptor, extensionClassDescriptor) &&
!ErrorUtils.isError(extensionClassDescriptor)) {
- val fqName = DescriptorUtils.getFqNameFromTopLevelClass(extensionClassDescriptor)
+ val fqName = DescriptorUtils.getFqNameSafe(extensionClassDescriptor)
return externalClassNodes.getOrPut(fqName, {
val newNode = DocumentationNode(fqName.asString(), Content.Empty, Kind.ExternalClass)
append(newNode, DocumentationReference.Kind.Member)
@@ -436,26 +488,23 @@ class DocumentationBuilder(val resolutionFacade: ResolutionFacade,
else -> Kind.Class
}
val node = DocumentationNode(this, kind)
- if (isInner) {
- node.appendTextNode("inner", Kind.Modifier)
- }
node.appendSupertypes(this)
if (getKind() != ClassKind.OBJECT && getKind() != ClassKind.ENUM_ENTRY) {
node.appendInPageChildren(typeConstructor.parameters, DocumentationReference.Kind.Detail)
val constructorsToDocument = if (getKind() == ClassKind.ENUM_CLASS)
- constructors.filter { it.valueParameters.size() > 0 }
+ constructors.filter { it.valueParameters.size > 0 }
else
constructors
- node.appendChildren(constructorsToDocument, DocumentationReference.Kind.Member)
+ node.appendMembers(constructorsToDocument)
}
val members = defaultType.memberScope.getAllDescriptors().filter { it != companionObjectDescriptor }
- node.appendChildren(members, DocumentationReference.Kind.Member)
+ node.appendMembers(members)
val companionObjectDescriptor = companionObjectDescriptor
if (companionObjectDescriptor != null) {
- node.appendChildren(companionObjectDescriptor.defaultType.memberScope.getAllDescriptors(),
- DocumentationReference.Kind.Member)
+ node.appendMembers(companionObjectDescriptor.defaultType.memberScope.getAllDescriptors())
}
node.appendAnnotations(this)
+ node.appendModifiers(this)
node.appendSourceLink(source)
register(this, node)
return node
@@ -498,8 +547,8 @@ class DocumentationBuilder(val resolutionFacade: ResolutionFacade,
node.appendInPageChildren(valueParameters, DocumentationReference.Kind.Detail)
node.appendType(returnType)
node.appendAnnotations(this)
+ node.appendModifiers(this)
node.appendSourceLink(source)
- node.appendOperatorOverloadNote(this)
overriddenDescriptors.forEach {
addOverrideLink(it, this)
@@ -520,64 +569,13 @@ class DocumentationBuilder(val resolutionFacade: ResolutionFacade,
}
}
- fun DocumentationNode.appendOperatorOverloadNote(descriptor: FunctionDescriptor) {
- val operatorName = descriptor.getImplementedOperator()
- if (operatorName != null) {
- val content = Content()
- content.append(ContentText("Implements "))
- content.strong {
- text("operator ")
- code {
- text(operatorName)
- }
- }
- val noteNode = DocumentationNode("", content, DocumentationNode.Kind.OverloadGroupNote)
- append(noteNode, DocumentationReference.Kind.Detail)
- }
- }
-
- fun FunctionDescriptor.getImplementedOperator(): String? {
- var arity = valueParameters.size()
- if (containingDeclaration is ClassDescriptor) {
- arity++
- }
- if (extensionReceiverParameter != null) {
- arity++
- }
-
- val token = if (arity == 2) {
- OperatorConventions.BINARY_OPERATION_NAMES.inverse()[name] ?:
- OperatorConventions.ASSIGNMENT_OPERATIONS.inverse()[name] ?:
- OperatorConventions.BOOLEAN_OPERATIONS.inverse()[name]
- } else if (arity == 1) {
- OperatorConventions.UNARY_OPERATION_NAMES.inverse()[name]
- }
- else null
-
- if (token is JetSingleValueToken) {
- return token.value
- }
-
- val name = name.asString()
- if (arity == 2 && name == "contains") {
- return "in"
- }
- if (arity >= 2 && (name == "get" || name == "set")) {
- return "[]"
- }
- if (arity == 2 && name == "equals" && valueParameters.size() == 1 &&
- KotlinBuiltIns.isNullableAny(valueParameters.first().type)) {
- return "=="
- }
- return null
- }
-
fun PropertyDescriptor.build(): DocumentationNode {
val node = DocumentationNode(this, if (inCompanionObject()) Kind.CompanionObjectProperty else Kind.Property)
node.appendInPageChildren(typeParameters, DocumentationReference.Kind.Detail)
extensionReceiverParameter?.let { node.appendChild(it, DocumentationReference.Kind.Detail) }
node.appendType(returnType)
node.appendAnnotations(this)
+ node.appendModifiers(this)
node.appendSourceLink(source)
if (isVar) {
node.appendTextNode("var", DocumentationNode.Kind.Modifier)
@@ -617,15 +615,9 @@ class DocumentationBuilder(val resolutionFacade: ResolutionFacade,
fun ValueParameterDescriptor.build(): DocumentationNode {
val node = DocumentationNode(this, Kind.Parameter)
- val varargType = varargElementType
- if (varargType != null) {
- node.appendTextNode("vararg", Kind.Annotation, DocumentationReference.Kind.Annotation)
- node.appendType(varargType)
- } else {
- node.appendType(type)
- }
- if (hasDefaultValue()) {
- val psi = source.getPsi() as? JetParameter
+ node.appendType(varargElementType ?: type)
+ if (declaresDefaultValue()) {
+ val psi = source.getPsi() as? KtParameter
if (psi != null) {
val defaultValueText = psi.defaultValue?.text
if (defaultValueText != null) {
@@ -634,6 +626,7 @@ class DocumentationBuilder(val resolutionFacade: ResolutionFacade,
}
}
node.appendAnnotations(this)
+ node.appendModifiers(this)
register(this, node)
return node
}
@@ -647,11 +640,14 @@ class DocumentationBuilder(val resolutionFacade: ResolutionFacade,
if (prefix != "") {
node.appendTextNode(prefix, Kind.Modifier)
}
+ if (isReified) {
+ node.appendTextNode("reified", Kind.Modifier)
+ }
- val builtIns = KotlinBuiltIns.getInstance()
for (constraint in upperBounds) {
- if (constraint == builtIns.defaultBound)
+ if (KotlinBuiltIns.isDefaultBound(constraint)) {
continue
+ }
node.appendType(constraint, Kind.UpperBound)
}
@@ -683,7 +679,7 @@ class DocumentationBuilder(val resolutionFacade: ResolutionFacade,
return null
}
val node = DocumentationNode(annotationClass.name.asString(), Content.Empty, DocumentationNode.Kind.Annotation)
- val arguments = allValueArguments.toList().sortBy { it.first.index }
+ val arguments = allValueArguments.toList().sortedBy { it.first.index }
arguments.forEach {
val valueNode = it.second.toDocumentationNode()
if (valueNode != null) {
@@ -695,6 +691,11 @@ class DocumentationBuilder(val resolutionFacade: ResolutionFacade,
return node
}
+ fun CompileTimeConstant<Any?>.build(): DocumentationNode? = when (this) {
+ is TypedCompileTimeConstant -> constantValue.toDocumentationNode()
+ else -> null
+ }
+
fun ConstantValue<*>.toDocumentationNode(): DocumentationNode? = value?.let { value ->
when (value) {
is String ->