From 778e2b3f7ff62971e18a49d81a8825e5dd894c2e Mon Sep 17 00:00:00 2001 From: Ilya Ryzhenkov Date: Mon, 29 Sep 2014 20:54:59 +0400 Subject: Extract content model, make doc model independent from descriptors, parse doccomments with custom parser, some tests failing due to hanging new lines. --- src/Analysis/CommentsAPI.kt | 2 +- src/Formats/MarkdownFormatService.kt | 4 - src/Formats/StructuredFormatService.kt | 24 ++-- src/Formats/TextFormatService.kt | 3 - src/Kotlin/ContentBuilder.kt | 79 +++++++++++++ src/Kotlin/Diagnostics.kt | 40 +++++++ src/Kotlin/DocumentationBuildingVisitor.kt | 122 ++++++++++++++++++++ src/Kotlin/DocumentationContext.kt | 47 ++++++++ src/Kotlin/DocumentationNodeBuilder.kt | 177 +++++++++++++++++++++++++++++ src/Markdown/MarkdownProcessor.kt | 62 ++++++---- src/Markdown/_MarkdownLexer.flex | 40 ------- src/Markdown/markdown.bnf | 42 +++---- src/Model/Content.kt | 88 ++++++++++++++ src/Model/Diagnostics.kt | 40 ------- src/Model/DocumentationBuildingVisitor.kt | 121 -------------------- src/Model/DocumentationContent.kt | 150 ------------------------ src/Model/DocumentationModule.kt | 23 +--- src/Model/DocumentationNode.kt | 7 +- src/Model/DocumentationNodeBuilder.kt | 153 ------------------------- 19 files changed, 627 insertions(+), 597 deletions(-) create mode 100644 src/Kotlin/ContentBuilder.kt create mode 100644 src/Kotlin/Diagnostics.kt create mode 100644 src/Kotlin/DocumentationBuildingVisitor.kt create mode 100644 src/Kotlin/DocumentationContext.kt create mode 100644 src/Kotlin/DocumentationNodeBuilder.kt delete mode 100644 src/Markdown/_MarkdownLexer.flex create mode 100644 src/Model/Content.kt delete mode 100644 src/Model/Diagnostics.kt delete mode 100644 src/Model/DocumentationBuildingVisitor.kt delete mode 100644 src/Model/DocumentationContent.kt delete mode 100644 src/Model/DocumentationNodeBuilder.kt (limited to 'src') diff --git a/src/Analysis/CommentsAPI.kt b/src/Analysis/CommentsAPI.kt index 5df4bd38..a17b6aa4 100644 --- a/src/Analysis/CommentsAPI.kt +++ b/src/Analysis/CommentsAPI.kt @@ -31,5 +31,5 @@ fun KDoc?.extractText(): String { comment.substring(0, comment.length - 2) else comment).trim() - }.filter { it.any() }.join("\n") + }.join("\n") } \ No newline at end of file diff --git a/src/Formats/MarkdownFormatService.kt b/src/Formats/MarkdownFormatService.kt index d7530a25..3b87835f 100644 --- a/src/Formats/MarkdownFormatService.kt +++ b/src/Formats/MarkdownFormatService.kt @@ -16,10 +16,6 @@ public open class MarkdownFormatService(locationService: LocationService, return text.htmlEscape() } - override public fun formatText(text: RichString): String { - return text.toString().htmlEscape() - } - override public fun formatCode(code: String): String { return "`$code`" } diff --git a/src/Formats/StructuredFormatService.kt b/src/Formats/StructuredFormatService.kt index 0c58f553..b1e614f6 100644 --- a/src/Formats/StructuredFormatService.kt +++ b/src/Formats/StructuredFormatService.kt @@ -28,19 +28,17 @@ public abstract class StructuredFormatService(val locationService: LocationServi public abstract fun formatCode(code: String): String public abstract fun formatBreadcrumbs(items: Iterable): String - open fun formatText(text: RichString): String { + open fun formatText(nodes: Iterable): String { + return nodes.map { formatText(it) }.join("") + } + + open fun formatText(text: ContentNode): String { return StringBuilder { - for (slice in text.slices) { - val style = slice.style - when (style) { - is NormalStyle -> append(slice.text) - is BoldStyle -> append(formatBold(slice.text)) - is CodeStyle -> append(formatCode(slice.text)) - is LinkStyle -> { - val node = resolutionService.resolve(style.link) - val location = locationService.location(node) - append(formatLink(slice.text, location)) - } + for (node in text.children) { + when (node) { + is ContentText -> append(node.text) + is ContentEmphasis -> append(formatBold(formatText(node.children))) + else -> append(formatText(node.children)) } } }.toString() @@ -67,7 +65,7 @@ public abstract class StructuredFormatService(val locationService: LocationServi if (label.startsWith("$")) continue appendLine(to, formatBold(formatText(label))) - appendLine(to, formatText(section.text)) + appendLine(to, formatText(section)) appendLine(to) } } diff --git a/src/Formats/TextFormatService.kt b/src/Formats/TextFormatService.kt index 77a0bb65..8fea5a6a 100644 --- a/src/Formats/TextFormatService.kt +++ b/src/Formats/TextFormatService.kt @@ -9,12 +9,9 @@ public class TextFormatService(val signatureGenerator: LanguageService) : Format appendln(signatureGenerator.render(node)) appendln() appendln(node.doc.summary) - for (n in 0..node.doc.summary.length()) - append("=") for ((label,section) in node.doc.sections) { appendln(label) - appendln(section.text) } } } diff --git a/src/Kotlin/ContentBuilder.kt b/src/Kotlin/ContentBuilder.kt new file mode 100644 index 00000000..78bd7eaf --- /dev/null +++ b/src/Kotlin/ContentBuilder.kt @@ -0,0 +1,79 @@ +package org.jetbrains.dokka + +import org.jetbrains.markdown.MarkdownElementTypes +import java.util.ArrayDeque + +public fun MarkdownTree.toContent(): Content { + val nodeStack = ArrayDeque() + nodeStack.push(Content()) + + visit {(node, text, processChildren) -> + val parent = nodeStack.peek()!! + val nodeType = node.getTokenType() + val nodeText = getNodeText(node) + when (nodeType) { + MarkdownElementTypes.BULLET_LIST -> { + nodeStack.push(ContentList()) + processChildren() + parent.children.add(nodeStack.pop()) + } + MarkdownElementTypes.ORDERED_LIST -> { + nodeStack.push(ContentList()) // TODO: add list kind + processChildren() + parent.children.add(nodeStack.pop()) + } + MarkdownElementTypes.HORIZONTAL_RULE -> { + } + MarkdownElementTypes.LIST_BLOCK -> { + nodeStack.push(ContentBlock()) + processChildren() + parent.children.add(nodeStack.pop()) + } + MarkdownElementTypes.EMPH -> { + nodeStack.push(ContentEmphasis()) + processChildren() + parent.children.add(nodeStack.pop()) + } + MarkdownElementTypes.STRONG -> { + nodeStack.push(ContentStrong()) + processChildren() + parent.children.add(nodeStack.pop()) + } + MarkdownElementTypes.ANONYMOUS_SECTION -> { + nodeStack.push(ContentSection("")) + processChildren() + parent.children.add(nodeStack.pop()) + } + MarkdownElementTypes.NAMED_SECTION -> { + val label = findChildByType(node, MarkdownElementTypes.SECTION_NAME)?.let { getNodeText(it) } ?: "" + nodeStack.push(ContentSection(label)) + processChildren() + parent.children.add(nodeStack.pop()) + } + MarkdownElementTypes.PLAIN_TEXT -> { + nodeStack.push(ContentText(nodeText)) + processChildren() + parent.children.add(nodeStack.pop()) + } + MarkdownElementTypes.END_LINE -> { + nodeStack.push(ContentText(nodeText)) + processChildren() + parent.children.add(nodeStack.pop()) + } + MarkdownElementTypes.BLANK_LINE -> { + processChildren() + } + MarkdownElementTypes.PARA -> { + nodeStack.push(ContentBlock()) + processChildren() + parent.children.add(nodeStack.pop()) + } + else -> { + processChildren() + } + } + } + return nodeStack.pop() as Content +} + + diff --git a/src/Kotlin/Diagnostics.kt b/src/Kotlin/Diagnostics.kt new file mode 100644 index 00000000..5548bc01 --- /dev/null +++ b/src/Kotlin/Diagnostics.kt @@ -0,0 +1,40 @@ +package org.jetbrains.dokka + +import org.jetbrains.jet.lang.descriptors.* +import org.jetbrains.jet.lang.resolve.name.* +import org.jetbrains.jet.lang.resolve.BindingContext + +fun DocumentationContext.checkResolveChildren(node: DocumentationNode) { + if (node.kind != DocumentationNode.Kind.Module && node.kind != DocumentationNode.Kind.Package) { + // TODO: we don't resolve packages and modules for now + + val parentScope = getResolutionScope(node) + for (item in node.details + node.members) { + val symbolName = item.name + val symbol: DeclarationDescriptor? = when (item.kind) { + DocumentationNode.Kind.Modifier -> continue // do not resolve modifiers, they are not names + DocumentationNode.Kind.Receiver -> continue // what is receiver's name in platform? + DocumentationNode.Kind.Parameter -> parentScope.getLocalVariable(Name.guess(symbolName)) + DocumentationNode.Kind.Function -> parentScope.getFunctions(Name.guess(symbolName)).firstOrNull() + DocumentationNode.Kind.Property -> parentScope.getProperties(Name.guess(symbolName)).firstOrNull() + DocumentationNode.Kind.Constructor -> parentScope.getFunctions(Name.guess(symbolName)).firstOrNull() + else -> parentScope.getClassifier(Name.guess(symbolName)) + } + + if (symbol == null) + println("WARNING: Cannot resolve $item in ${path(node)}") + } + } + + for (reference in node.allReferences().filterNot { it.kind == DocumentationReference.Kind.Owner }) { + checkResolveChildren(reference.to) + } +} + +fun path(node: DocumentationNode): String { + val owner = node.owner + if (owner != null) + return "$node in ${path(owner)}" + else + return "$node" +} \ No newline at end of file diff --git a/src/Kotlin/DocumentationBuildingVisitor.kt b/src/Kotlin/DocumentationBuildingVisitor.kt new file mode 100644 index 00000000..5654903b --- /dev/null +++ b/src/Kotlin/DocumentationBuildingVisitor.kt @@ -0,0 +1,122 @@ +package org.jetbrains.dokka + +import org.jetbrains.jet.lang.descriptors.* +import org.jetbrains.jet.lang.resolve.name.* +import org.jetbrains.jet.lang.resolve.* + +public data class DocumentationOptions(val includeNonPublic : Boolean = false) + +class DocumentationBuildingVisitor(val context: BindingContext, + val options: DocumentationOptions, + private val worker: DeclarationDescriptorVisitor) +: DeclarationDescriptorVisitor { + + private fun visitChildren(descriptors: Collection, data: DocumentationNode) { + for (descriptor in descriptors) { + visitChild(descriptor, data) + } + } + + private fun visitChild(descriptor: DeclarationDescriptor?, data: DocumentationNode) { + if (descriptor != null && descriptor.isUserCode()) { + if (options.includeNonPublic || descriptor !is MemberDescriptor || descriptor.getVisibility().isPublicAPI()) { + descriptor.accept(this, data) + } + } + } + + private fun createDocumentation(descriptor: DeclarationDescriptor, data: DocumentationNode): DocumentationNode { + return descriptor.accept(worker, data) + } + + private fun processCallable(descriptor: CallableDescriptor, data: DocumentationNode): DocumentationNode { + val node = createDocumentation(descriptor, data) + visitChildren(descriptor.getTypeParameters(), node) + visitChild(descriptor.getReceiverParameter(), node) + visitChildren(descriptor.getValueParameters(), node) + return node + } + + public override fun visitPackageFragmentDescriptor(descriptor: PackageFragmentDescriptor?, data: DocumentationNode?): DocumentationNode? { + val node = createDocumentation(descriptor!!, data!!) + visitChildren(descriptor.getMemberScope().getAllDescriptors(), node) + return node + } + + public override fun visitPackageViewDescriptor(descriptor: PackageViewDescriptor?, data: DocumentationNode?): DocumentationNode? { + val node = createDocumentation(descriptor!!, data!!) + visitChildren(descriptor.getMemberScope().getAllDescriptors(), node) + return node + } + + public override fun visitVariableDescriptor(descriptor: VariableDescriptor?, data: DocumentationNode?): DocumentationNode? { + val node = processCallable(descriptor!!, data!!) + return node + } + + public override fun visitPropertyDescriptor(descriptor: PropertyDescriptor?, data: DocumentationNode?): DocumentationNode? { + val node = processCallable(descriptor!!, data!!) + visitChild(descriptor.getGetter(), node) + visitChild(descriptor.getSetter(), node) + return node + } + + public override fun visitFunctionDescriptor(descriptor: FunctionDescriptor?, data: DocumentationNode?): DocumentationNode? { + val node = processCallable(descriptor!!, data!!) + return node + } + + public override fun visitTypeParameterDescriptor(descriptor: TypeParameterDescriptor?, data: DocumentationNode?): DocumentationNode? { + val node = createDocumentation(descriptor!!, data!!) + return node + } + + public override fun visitClassDescriptor(descriptor: ClassDescriptor?, data: DocumentationNode?): DocumentationNode? { + val node = createDocumentation(descriptor!!, data!!) + if (descriptor.getKind() != ClassKind.OBJECT) { + // do not go inside object for class object and constructors, they are generated + visitChildren(descriptor.getTypeConstructor().getParameters(), node) + visitChildren(descriptor.getConstructors(), node) + visitChild(descriptor.getClassObjectDescriptor(), node) + } + visitChildren(descriptor.getDefaultType().getMemberScope().getAllDescriptors(), node) + return node + } + + public override fun visitModuleDeclaration(descriptor: ModuleDescriptor, data: DocumentationNode): DocumentationNode { + val node = createDocumentation(descriptor, data) + visitChild(descriptor.getPackage(FqName.ROOT), node) + return node + } + + public override fun visitConstructorDescriptor(descriptor: ConstructorDescriptor?, data: DocumentationNode?): DocumentationNode? { + val node = visitFunctionDescriptor(descriptor!!, data) + return node + } + + public override fun visitScriptDescriptor(scriptDescriptor: ScriptDescriptor?, data: DocumentationNode?): DocumentationNode? { + val classDescriptor = scriptDescriptor!!.getClassDescriptor() + val node = visitClassDescriptor(classDescriptor, data) + return node + } + + public override fun visitValueParameterDescriptor(descriptor: ValueParameterDescriptor?, data: DocumentationNode?): DocumentationNode? { + val node = visitVariableDescriptor(descriptor!!, data) + return node + } + + public override fun visitPropertyGetterDescriptor(descriptor: PropertyGetterDescriptor?, data: DocumentationNode?): DocumentationNode? { + val node = visitFunctionDescriptor(descriptor!!, data) + return node + } + + public override fun visitPropertySetterDescriptor(descriptor: PropertySetterDescriptor?, data: DocumentationNode?): DocumentationNode? { + val node = visitFunctionDescriptor(descriptor!!, data) + return node + } + + public override fun visitReceiverParameterDescriptor(descriptor: ReceiverParameterDescriptor?, data: DocumentationNode?): DocumentationNode? { + val node = createDocumentation(descriptor!!, data!!) + return node + } +} diff --git a/src/Kotlin/DocumentationContext.kt b/src/Kotlin/DocumentationContext.kt new file mode 100644 index 00000000..1491aa2d --- /dev/null +++ b/src/Kotlin/DocumentationContext.kt @@ -0,0 +1,47 @@ +package org.jetbrains.dokka + +import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor +import org.jetbrains.jet.lang.resolve.BindingContext +import org.jetbrains.jet.lang.resolve.scopes.JetScope +import org.jetbrains.jet.lang.descriptors.ModuleDescriptor +import org.jetbrains.jet.lang.resolve.name.FqName + +public class DocumentationContext(val bindingContext: BindingContext) { + val descriptorToNode = hashMapOf() + val nodeToDescriptor = hashMapOf() + + fun register(descriptor: DeclarationDescriptor, node: DocumentationNode) { + descriptorToNode.put(descriptor, node) + nodeToDescriptor.put(node, descriptor) + } + + fun getResolutionScope(node: DocumentationNode): JetScope { + val descriptor = nodeToDescriptor[node] ?: throw IllegalArgumentException("Node is not known to this context") + return bindingContext.getResolutionScope(descriptor) + } + + fun parseDocumentation(descriptor: DeclarationDescriptor): Content { + val docText = bindingContext.getDocumentationElements(descriptor).map { it.extractText() }.join("\n") + val tree = MarkdownProcessor.parse(docText) + println(tree.toTestString()) + val content = tree.toContent() + return content + } +} + +fun BindingContext.createDocumentationModule(name: String, + module: ModuleDescriptor, + packages: Set, + options: DocumentationOptions = DocumentationOptions()): DocumentationModule { + val documentationModule = DocumentationModule(name) + val context = DocumentationContext(this) + val visitor = DocumentationNodeBuilder(context) + for (packageName in packages) { + val pkg = module.getPackage(packageName) + pkg!!.accept(DocumentationBuildingVisitor(this, options, visitor), documentationModule) + } + + // TODO: Uncomment for resolve verification + // checkResolveChildren(documentationModule) + return documentationModule +} diff --git a/src/Kotlin/DocumentationNodeBuilder.kt b/src/Kotlin/DocumentationNodeBuilder.kt new file mode 100644 index 00000000..535f037f --- /dev/null +++ b/src/Kotlin/DocumentationNodeBuilder.kt @@ -0,0 +1,177 @@ +package org.jetbrains.dokka + +import org.jetbrains.jet.lang.descriptors.impl.DeclarationDescriptorVisitorEmptyBodies +import org.jetbrains.jet.lang.descriptors.MemberDescriptor +import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor +import org.jetbrains.jet.lang.types.JetType +import org.jetbrains.jet.lang.descriptors.Named +import org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor +import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor +import org.jetbrains.jet.lang.descriptors.ClassDescriptor +import org.jetbrains.jet.lang.descriptors.FunctionDescriptor +import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor +import org.jetbrains.jet.lang.descriptors.PropertyDescriptor +import org.jetbrains.jet.lang.descriptors.ConstructorDescriptor +import org.jetbrains.jet.lang.descriptors.PackageViewDescriptor +import org.jetbrains.jet.lang.descriptors.PackageFragmentDescriptor +import org.jetbrains.jet.lang.descriptors.ClassKind +import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns + +class DocumentationNodeBuilder(val context: DocumentationContext) : DeclarationDescriptorVisitorEmptyBodies() { + + fun reference(from: DocumentationNode, to: DocumentationNode, kind: DocumentationReference.Kind) { + from.addReferenceTo(to, kind) + if (kind == DocumentationReference.Kind.Link) + to.addReferenceTo(from, DocumentationReference.Kind.Link) + else + to.addReferenceTo(from, DocumentationReference.Kind.Owner) + } + + fun addModality(descriptor: MemberDescriptor, data: DocumentationNode) { + val modifier = descriptor.getModality().name().toLowerCase() + val node = DocumentationNode(modifier, Content.Empty, DocumentationNode.Kind.Modifier) + reference(data, node, DocumentationReference.Kind.Detail) + } + + fun addVisibility(descriptor: MemberDescriptor, data: DocumentationNode) { + val modifier = descriptor.getVisibility().toString() + val node = DocumentationNode(modifier, Content.Empty, DocumentationNode.Kind.Modifier) + reference(data, node, DocumentationReference.Kind.Detail) + } + + fun addType(descriptor: DeclarationDescriptor, t: JetType?, data: DocumentationNode) { + if (t == null) + return + val typeConstructor = t.getConstructor() + val classifierDescriptor = typeConstructor.getDeclarationDescriptor() + val name = when (classifierDescriptor) { + is Named -> classifierDescriptor.getName().asString() + else -> "" + } + val node = DocumentationNode(name, Content.Empty, DocumentationNode.Kind.Type) + reference(data, node, DocumentationReference.Kind.Detail) + + for (param in t.getArguments()) + addType(descriptor, param.getType(), node) + } + + override fun visitDeclarationDescriptor(descriptor: DeclarationDescriptor?, data: DocumentationNode?): DocumentationNode? { + descriptor!! + val doc = context.parseDocumentation(descriptor) + val node = DocumentationNode(descriptor.getName().asString(), doc, DocumentationNode.Kind.Unknown) + reference(data!!, node, DocumentationReference.Kind.Link) + context.register(descriptor, node) + return node + } + + override fun visitReceiverParameterDescriptor(descriptor: ReceiverParameterDescriptor?, data: DocumentationNode?): DocumentationNode? { + descriptor!! + val node = DocumentationNode(descriptor.getName().asString(), Content.Empty, DocumentationNode.Kind.Receiver) + reference(data!!, node, DocumentationReference.Kind.Detail) + + addType(descriptor, descriptor.getType(), node) + + return node + } + + override fun visitValueParameterDescriptor(descriptor: ValueParameterDescriptor?, data: DocumentationNode?): DocumentationNode? { + descriptor!! + val doc = context.parseDocumentation(descriptor) + val node = DocumentationNode(descriptor.getName().asString(), doc, DocumentationNode.Kind.Parameter) + reference(data!!, node, DocumentationReference.Kind.Detail) + + addType(descriptor, descriptor.getType(), node) + + return node + } + + override fun visitClassDescriptor(descriptor: ClassDescriptor?, data: DocumentationNode?): DocumentationNode? { + descriptor!! + val doc = context.parseDocumentation(descriptor) + val node = DocumentationNode(descriptor.getName().asString(), doc, when (descriptor.getKind()) { + ClassKind.OBJECT -> org.jetbrains.dokka.DocumentationNode.Kind.Object + ClassKind.CLASS_OBJECT -> org.jetbrains.dokka.DocumentationNode.Kind.Object + ClassKind.TRAIT -> org.jetbrains.dokka.DocumentationNode.Kind.Interface + ClassKind.ENUM_CLASS -> org.jetbrains.dokka.DocumentationNode.Kind.Enum + ClassKind.ENUM_ENTRY -> org.jetbrains.dokka.DocumentationNode.Kind.EnumItem + else -> DocumentationNode.Kind.Class + }) + reference(data!!, node, DocumentationReference.Kind.Member) + addModality(descriptor, node) + addVisibility(descriptor, node) + context.register(descriptor, node) + return node + } + + override fun visitFunctionDescriptor(descriptor: FunctionDescriptor?, data: DocumentationNode?): DocumentationNode? { + descriptor!! + val doc = context.parseDocumentation(descriptor) + val node = DocumentationNode(descriptor.getName().asString(), doc, DocumentationNode.Kind.Function) + reference(data!!, node, DocumentationReference.Kind.Member) + + addType(descriptor, descriptor.getReturnType(), node) + addModality(descriptor, node) + addVisibility(descriptor, node) + context.register(descriptor, node) + return node + } + + override fun visitTypeParameterDescriptor(descriptor: TypeParameterDescriptor?, data: DocumentationNode?): DocumentationNode? { + descriptor!! + val doc = context.parseDocumentation(descriptor) + val node = DocumentationNode(descriptor.getName().asString(), doc, DocumentationNode.Kind.TypeParameter) + reference(data!!, node, DocumentationReference.Kind.Detail) + val builtIns = KotlinBuiltIns.getInstance() + for (constraint in descriptor.getUpperBounds()) { + if (constraint == builtIns.getDefaultBound()) + continue + val constraintNode = DocumentationNode(constraint.toString(), Content.Empty, DocumentationNode.Kind.UpperBound) + reference(node, constraintNode, DocumentationReference.Kind.Detail) + } + for (constraint in descriptor.getLowerBounds()) { + if (builtIns.isNothing(constraint)) + continue + val constraintNode = DocumentationNode(constraint.toString(), Content.Empty, DocumentationNode.Kind.LowerBound) + reference(node, constraintNode, DocumentationReference.Kind.Detail) + } + return node + } + + override fun visitPropertyDescriptor(descriptor: PropertyDescriptor?, data: DocumentationNode?): DocumentationNode? { + descriptor!! + val doc = context.parseDocumentation(descriptor) + val node = DocumentationNode(descriptor.getName().asString(), doc, DocumentationNode.Kind.Property) + reference(data!!, node, DocumentationReference.Kind.Member) + + addType(descriptor, descriptor.getType(), node) + addModality(descriptor, node) + addVisibility(descriptor, node) + context.register(descriptor, node) + return node + } + + override fun visitConstructorDescriptor(descriptor: ConstructorDescriptor?, data: DocumentationNode?): DocumentationNode? { + descriptor!! + val doc = context.parseDocumentation(descriptor) + val node = DocumentationNode(descriptor.getName().asString(), doc, DocumentationNode.Kind.Constructor) + reference(data!!, node, DocumentationReference.Kind.Member) + + addVisibility(descriptor, node) + context.register(descriptor, node) + return node + } + + override fun visitPackageViewDescriptor(descriptor: PackageViewDescriptor?, data: DocumentationNode?): DocumentationNode? { + descriptor!! + val node = DocumentationNode(descriptor.getFqName().asString(), Content.Empty, DocumentationNode.Kind.Package) + reference(data!!, node, DocumentationReference.Kind.Member) + return node + } + + override fun visitPackageFragmentDescriptor(descriptor: PackageFragmentDescriptor?, data: DocumentationNode?): DocumentationNode? { + descriptor!! + val node = DocumentationNode(descriptor.fqName.asString(), Content.Empty, DocumentationNode.Kind.Package) + reference(data!!, node, DocumentationReference.Kind.Member) + return node + } +} \ No newline at end of file diff --git a/src/Markdown/MarkdownProcessor.kt b/src/Markdown/MarkdownProcessor.kt index fe6e8436..19d5a8fb 100644 --- a/src/Markdown/MarkdownProcessor.kt +++ b/src/Markdown/MarkdownProcessor.kt @@ -9,12 +9,11 @@ import com.intellij.lang.LighterASTNode import com.intellij.util.diff.FlyweightCapableTreeStructure import com.intellij.openapi.util.Ref import org.jetbrains.markdown.lexer.MarkdownLexer +import com.intellij.psi.tree.IElementType -public class MarkdownProcessor { - class object { - val EXPR_LANGUAGE = object : Language("MARKDOWN") {} - val DOCUMENT = IFileElementType("DOCUMENT", EXPR_LANGUAGE); - } +public object MarkdownProcessor { + val EXPR_LANGUAGE = object : Language("MARKDOWN") {} + val DOCUMENT = IFileElementType("DOCUMENT", EXPR_LANGUAGE); public fun parse(markdown: String): MarkdownTree { val parser = MarkdownParser() @@ -30,6 +29,28 @@ public class MarkdownTree(private val text: String, private val structure: Flywe visit(structure.getRoot(), action) } + fun findChildByType(node: LighterASTNode, findType: IElementType) : LighterASTNode? { + val ref = Ref.create?>() + val count = structure.getChildren(node, ref) + val children = ref.get() + if (children != null) { + for (index in 0..count - 1) { + val child = children[index] + val nodeType = child.getTokenType() + if (nodeType == findType) + return child + val nestedChild = findChildByType(child, findType) + if (nestedChild != null) + return nestedChild + } + } + return null + } + + fun getNodeText(node: LighterASTNode) : String { + return text.substring(node.getStartOffset(), node.getEndOffset()) + } + fun visit(node: LighterASTNode, action: (LighterASTNode, String, visitChildren: () -> Unit) -> Unit) { action(node, text) { val ref = Ref.create?>() @@ -46,7 +67,7 @@ public class MarkdownTree(private val text: String, private val structure: Flywe } -public fun MarkdownTree.dump(): String { +public fun MarkdownTree.toTestString(): String { val sb = StringBuilder() var level = 0 visit {(node, text, visitChildren) -> @@ -64,29 +85,25 @@ public fun MarkdownTree.dump(): String { public fun MarkdownTree.toHtml(): String { val sb = StringBuilder() - var level = 0 visit {(node, text, processChildren) -> val nodeType = node.getTokenType() val nodeText = text.substring(node.getStartOffset(), node.getEndOffset()) - val indent = " ".repeat(level * 2) when (nodeType) { MarkdownElementTypes.BULLET_LIST -> { - sb.appendln("$indent
    ") - level++ + sb.appendln("
      ") processChildren() - level-- - sb.appendln("$indent
    ") + sb.appendln("
") } MarkdownElementTypes.HORIZONTAL_RULE -> { - sb.appendln("$indent
") + sb.appendln("
") } MarkdownElementTypes.ORDERED_LIST -> { - sb.appendln("$indent
    ") + sb.appendln("
      ") processChildren() - sb.appendln("$indent
    ") + sb.appendln("
") } MarkdownElementTypes.LIST_BLOCK -> { - sb.append("$indent
  • ") + sb.append("
  • ") processChildren() sb.appendln("
  • ") } @@ -110,14 +127,9 @@ public fun MarkdownTree.toHtml(): String { sb.appendln() } MarkdownElementTypes.PARA -> { - sb.appendln("$indent

    ") - processChildren() - sb.appendln("$indent

    ") - } - MarkdownElementTypes.VERBATIM -> { - sb.appendln("$indent
    ")
    +                sb.append("

    ") processChildren() - sb.appendln("$indent

    ") + sb.appendln("

    ") } else -> { processChildren() @@ -129,8 +141,8 @@ public fun MarkdownTree.toHtml(): String { fun markdownToHtml(markdown: String): String { - val markdownTree = MarkdownProcessor().parse(markdown) - val ast = markdownTree.dump() + val markdownTree = MarkdownProcessor.parse(markdown) + val ast = markdownTree.toTestString() return markdownTree.toHtml() } diff --git a/src/Markdown/_MarkdownLexer.flex b/src/Markdown/_MarkdownLexer.flex deleted file mode 100644 index 0a15e41a..00000000 --- a/src/Markdown/_MarkdownLexer.flex +++ /dev/null @@ -1,40 +0,0 @@ -package org.jetbrains.markdown.lexer; - -import com.intellij.lexer.*; -import com.intellij.psi.tree.IElementType; -import static org.jetbrains.markdown.MarkdownElementTypes.*; - -%% - -%{ - public _MarkdownLexer() { - this((java.io.Reader)null); - } -%} - -%public -%class _MarkdownLexer -%implements FlexLexer -%function advance -%type IElementType -%unicode - -Newline="\r"|"\n"|"\r\n" -Spacechar=[\ \t\f] -Number=[0-9]+(\.[0-9]*)? -String=[^~\*_`&\[\]() { - {Spacechar} { return SPACECHAR; } - {Newline} { return NEWLINE; } - "\\357\\273\\277" { return BOM; } - - {Number} { return NUMBER; } - {String} { return STRING; } - {AnyChar} { return ANYCHAR; } - - [^] { return com.intellij.psi.TokenType.BAD_CHARACTER; } -} diff --git a/src/Markdown/markdown.bnf b/src/Markdown/markdown.bnf index ca254295..79e9e0b4 100644 --- a/src/Markdown/markdown.bnf +++ b/src/Markdown/markdown.bnf @@ -21,35 +21,35 @@ } -Document ::= BOM? ( Block )* +Document ::= BOM? Whitespace* AnonymousSection? (Whitespace* NamedSection)* -private OptionalSpace ::= Spacechar* -private RequiredSpace ::= Spacechar+ -private NonindentSpace ::= (" " | " " | " ")? +AnonymousSection ::= SectionBody +NamedSection ::= SectionHeader SectionBody +private SectionHeader ::= '$' SectionName OptionalSpace ':' OptionalSpace +SectionName ::= SectionNameStart | '{' OptionalSpace SectionNameStart (Spacechar+ String)* OptionalSpace '}' +private SectionNameStart ::= '$'? String +SectionBody::= Block* BlankLine ::= OptionalSpace Newline Whitespace ::= Spacechar | Newline +private OptionalSpace ::= Spacechar* +private NonindentSpace ::= (" " | " " | " ")? + EndLine ::= TerminalEndline | NormalEndline -private NormalEndline ::= OptionalSpace Newline !BlankLine -private TerminalEndline ::= (OptionalSpace Newline <>) | (OptionalSpace <>) +private NormalEndline ::= Newline !BlankLine +private TerminalEndline ::= OptionalSpace <> private Indent ::= "\t" | " " -NonblankIndentedLine ::= !BlankLine IndentedLine -IndentedLine ::= Indent PlainText // ---- BLOCKS ---- -private Block ::= BlankLine* ( - Para - | Verbatim - | OrderedList - | BulletList - | Inlines - ) - -Para ::= NonindentSpace Inlines (BlankLine | TerminalEndline) +Block ::= BlankLine* ( + OrderedList + | BulletList + | HorizontalRule + | Para + ) -Verbatim ::= VerbatimItem+ -VerbatimItem ::= BlankLine* NonblankIndentedLine +Para ::= Inlines (BlankLine | TerminalEndline)? HorizontalRule ::= NonindentSpace ( '*' OptionalSpace '*' OptionalSpace '*' (OptionalSpace '*')* @@ -74,8 +74,8 @@ ListContinuationBlock ::= BlankLine* (Indent ListBlock)+ // ---- INLINES ---- private Inlines ::= (!EndLine Inline | EndLine &Inline )+ EndLine? -private Inline ::= Strong | Emph | Link | PlainText -PlainText ::= (String | Number | Spacechar)+ +Inline ::= Strong | Emph | Link | PlainText +PlainText ::= (String | Number | Spacechar+)+ Emph ::= EmphStar | EmphUnderscore private EmphStar ::= '*' !Whitespace (!'*' Inline)+ '*' diff --git a/src/Model/Content.kt b/src/Model/Content.kt new file mode 100644 index 00000000..eb092cb2 --- /dev/null +++ b/src/Model/Content.kt @@ -0,0 +1,88 @@ +package org.jetbrains.dokka + +import kotlin.properties.Delegates + +public abstract class ContentNode { + val children = arrayListOf() + + class object { + val empty = ContentEmpty + } + + fun isEmpty() = children.isEmpty() +} + +public object ContentEmpty : ContentNode( ) + +public class ContentText(val text : String) : ContentNode( ) +public class ContentBlock() : ContentNode( ) +public class ContentEmphasis() : ContentNode() +public class ContentStrong() : ContentNode() +public class ContentList() : ContentNode() +public class ContentSection(public val label: String) : ContentNode() + +public class Content() : ContentNode() { + public val sections: Map by Delegates.lazy { + val map = hashMapOf() + for (child in children) { + if (child is ContentSection) + map.put(child.label, child) + } + + if ("\$summary" !in map && "\$description" !in map) { + // no explicit summary and description, convert anonymous section + val anonymous = map[""] + if (anonymous != null) { + map.remove("") + val summary = ContentSection("\$summary") + val description = ContentSection("\$description") + + val summaryNodes = anonymous.children.take(1) + val descriptionNodes = anonymous.children.drop(1) + + if (summaryNodes.any()) { + summary.children.addAll(summaryNodes) + map.put("\$summary", summary) + } + + if (descriptionNodes.any()) { + description.children.addAll(descriptionNodes) + map.put("\$description", description) + } + } + } + map + } + + public val summary: ContentNode get() = sections["\$summary"] ?: ContentNode.empty + public val description: ContentNode get() = sections["\$description"] ?: ContentNode.empty + + override fun equals(other: Any?): Boolean { + if (other !is Content) + return false + if (sections.size != other.sections.size) + return false + for (keys in sections.keySet()) + if (sections[keys] != other.sections[keys]) + return false + + return true + } + + override fun hashCode(): Int { + return sections.map { it.hashCode() }.sum() + } + + override fun toString(): String { + if (sections.isEmpty()) + return "" + return sections.values().joinToString() + } + + val isEmpty: Boolean + get() = sections.none() + + class object { + val Empty = Content() + } +} diff --git a/src/Model/Diagnostics.kt b/src/Model/Diagnostics.kt deleted file mode 100644 index 1077da7c..00000000 --- a/src/Model/Diagnostics.kt +++ /dev/null @@ -1,40 +0,0 @@ -package org.jetbrains.dokka - -import org.jetbrains.jet.lang.descriptors.* -import org.jetbrains.jet.lang.resolve.name.* -import org.jetbrains.jet.lang.resolve.BindingContext - -fun BindingContext.checkResolveChildren(node: DocumentationNode) { - if (node.kind != DocumentationNode.Kind.Module && node.kind != DocumentationNode.Kind.Package) { - // TODO: we don't resolve packages and modules for now - - val parentScope = getResolutionScope(node.descriptor) - for (item in node.details + node.members) { - val symbolName = item.name - val symbol: DeclarationDescriptor? = when (item.kind) { - DocumentationNode.Kind.Modifier -> continue // do not resolve modifiers, they are not names - DocumentationNode.Kind.Receiver -> continue // what is receiver's name in platform? - DocumentationNode.Kind.Parameter -> parentScope.getLocalVariable(Name.guess(symbolName)) - DocumentationNode.Kind.Function -> parentScope.getFunctions(Name.guess(symbolName)).firstOrNull() - DocumentationNode.Kind.Property -> parentScope.getProperties(Name.guess(symbolName)).firstOrNull() - DocumentationNode.Kind.Constructor -> parentScope.getFunctions(Name.guess(symbolName)).firstOrNull() - else -> parentScope.getClassifier(Name.guess(symbolName)) - } - - if (symbol == null) - println("WARNING: Cannot resolve $item in ${path(node)}") - } - } - - for (reference in node.allReferences().filterNot { it.kind == DocumentationReference.Kind.Owner }) { - checkResolveChildren(reference.to) - } -} - -fun path(node: DocumentationNode): String { - val owner = node.owner - if (owner != null) - return "$node in ${path(owner)}" - else - return "$node" -} \ No newline at end of file diff --git a/src/Model/DocumentationBuildingVisitor.kt b/src/Model/DocumentationBuildingVisitor.kt deleted file mode 100644 index 6118b0f5..00000000 --- a/src/Model/DocumentationBuildingVisitor.kt +++ /dev/null @@ -1,121 +0,0 @@ -package org.jetbrains.dokka - -import org.jetbrains.jet.lang.descriptors.* -import org.jetbrains.jet.lang.resolve.name.* -import org.jetbrains.jet.lang.resolve.* - -public data class DocumentationOptions(val includeNonPublic : Boolean = false) -class DocumentationBuildingVisitor(val context: BindingContext, - val options: DocumentationOptions, - private val worker: DeclarationDescriptorVisitor) -: DeclarationDescriptorVisitor { - - private fun visitChildren(descriptors: Collection, data: DocumentationNode) { - for (descriptor in descriptors) { - visitChild(descriptor, data) - } - } - - private fun visitChild(descriptor: DeclarationDescriptor?, data: DocumentationNode) { - if (descriptor != null && descriptor.isUserCode()) { - if (options.includeNonPublic || descriptor !is MemberDescriptor || descriptor.getVisibility().isPublicAPI()) { - descriptor.accept(this, data) - } - } - } - - private fun createDocumentation(descriptor: DeclarationDescriptor, data: DocumentationNode): DocumentationNode { - return descriptor.accept(worker, data) - } - - private fun processCallable(descriptor: CallableDescriptor, data: DocumentationNode): DocumentationNode { - val node = createDocumentation(descriptor, data) - visitChildren(descriptor.getTypeParameters(), node) - visitChild(descriptor.getReceiverParameter(), node) - visitChildren(descriptor.getValueParameters(), node) - return node - } - - public override fun visitPackageFragmentDescriptor(descriptor: PackageFragmentDescriptor?, data: DocumentationNode?): DocumentationNode? { - val node = createDocumentation(descriptor!!, data!!) - visitChildren(descriptor.getMemberScope().getAllDescriptors(), node) - return node - } - - public override fun visitPackageViewDescriptor(descriptor: PackageViewDescriptor?, data: DocumentationNode?): DocumentationNode? { - val node = createDocumentation(descriptor!!, data!!) - visitChildren(descriptor.getMemberScope().getAllDescriptors(), node) - return node - } - - public override fun visitVariableDescriptor(descriptor: VariableDescriptor?, data: DocumentationNode?): DocumentationNode? { - val node = processCallable(descriptor!!, data!!) - return node - } - - public override fun visitPropertyDescriptor(descriptor: PropertyDescriptor?, data: DocumentationNode?): DocumentationNode? { - val node = processCallable(descriptor!!, data!!) - visitChild(descriptor.getGetter(), node) - visitChild(descriptor.getSetter(), node) - return node - } - - public override fun visitFunctionDescriptor(descriptor: FunctionDescriptor?, data: DocumentationNode?): DocumentationNode? { - val node = processCallable(descriptor!!, data!!) - return node - } - - public override fun visitTypeParameterDescriptor(descriptor: TypeParameterDescriptor?, data: DocumentationNode?): DocumentationNode? { - val node = createDocumentation(descriptor!!, data!!) - return node - } - - public override fun visitClassDescriptor(descriptor: ClassDescriptor?, data: DocumentationNode?): DocumentationNode? { - val node = createDocumentation(descriptor!!, data!!) - if (descriptor.getKind() != ClassKind.OBJECT) { - // do not go inside object for class object and constructors, they are generated - visitChildren(descriptor.getTypeConstructor().getParameters(), node) - visitChildren(descriptor.getConstructors(), node) - visitChild(descriptor.getClassObjectDescriptor(), node) - } - visitChildren(descriptor.getDefaultType().getMemberScope().getAllDescriptors(), node) - return node - } - - public override fun visitModuleDeclaration(descriptor: ModuleDescriptor, data: DocumentationNode): DocumentationNode { - val node = createDocumentation(descriptor, data) - visitChild(descriptor.getPackage(FqName.ROOT), node) - return node - } - - public override fun visitConstructorDescriptor(descriptor: ConstructorDescriptor?, data: DocumentationNode?): DocumentationNode? { - val node = visitFunctionDescriptor(descriptor!!, data) - return node - } - - public override fun visitScriptDescriptor(scriptDescriptor: ScriptDescriptor?, data: DocumentationNode?): DocumentationNode? { - val classDescriptor = scriptDescriptor!!.getClassDescriptor() - val node = visitClassDescriptor(classDescriptor, data) - return node - } - - public override fun visitValueParameterDescriptor(descriptor: ValueParameterDescriptor?, data: DocumentationNode?): DocumentationNode? { - val node = visitVariableDescriptor(descriptor!!, data) - return node - } - - public override fun visitPropertyGetterDescriptor(descriptor: PropertyGetterDescriptor?, data: DocumentationNode?): DocumentationNode? { - val node = visitFunctionDescriptor(descriptor!!, data) - return node - } - - public override fun visitPropertySetterDescriptor(descriptor: PropertySetterDescriptor?, data: DocumentationNode?): DocumentationNode? { - val node = visitFunctionDescriptor(descriptor!!, data) - return node - } - - public override fun visitReceiverParameterDescriptor(descriptor: ReceiverParameterDescriptor?, data: DocumentationNode?): DocumentationNode? { - val node = createDocumentation(descriptor!!, data!!) - return node - } -} diff --git a/src/Model/DocumentationContent.kt b/src/Model/DocumentationContent.kt deleted file mode 100644 index 77e8c764..00000000 --- a/src/Model/DocumentationContent.kt +++ /dev/null @@ -1,150 +0,0 @@ -package org.jetbrains.dokka - -import org.jetbrains.jet.lang.descriptors.* -import org.jetbrains.jet.lang.resolve.BindingContext - -public class DocumentationContentSection(public val label: String, public val text: RichString) { - override fun toString(): String { - return "$label = $text" - } -} - -public class DocumentationContent(public val sections: Map) { - - public val summary: RichString get() = sections["\$summary"]?.text ?: RichString.empty - public val description: RichString get() = sections["\$description"]?.text ?: RichString.empty - - override fun equals(other: Any?): Boolean { - if (other !is DocumentationContent) - return false - if (sections.size != other.sections.size) - return false - for (keys in sections.keySet()) - if (sections[keys] != other.sections[keys]) - return false - - return true - } - - override fun hashCode(): Int { - return sections.map { it.hashCode() }.sum() - } - - override fun toString(): String { - if (sections.isEmpty()) - return "" - return sections.values().joinToString() - } - - val isEmpty: Boolean - get() = description.isEmpty() && sections.none() - - class object { - val Empty = DocumentationContent(mapOf()) - } -} - - -fun BindingContext.getDocumentation(descriptor: DeclarationDescriptor): DocumentationContent { - val docText = getDocumentationElements(descriptor).map { it.extractText() }.join("\n") - val sections = docText.parseSections() - sections.createSummaryAndDescription() - return DocumentationContent(sections) -} - -fun MutableMap.createSummaryAndDescription() { - - val summary = get("\$summary") - val description = get("\$description") - if (summary != null && description == null) { - return - } - - if (summary == null && description != null) { - return - } - - val unnamed = get("") - if (unnamed == null) { - return - } - - val split = unnamed.text.splitBy("\n") - remove("") - if (!split.first.isEmpty()) - put("\$summary", DocumentationContentSection("\$summary", split.first)) - if (!split.second.isEmpty()) - put("\$description", DocumentationContentSection("\$description", split.second)) -} - -fun String.parseLabel(index: Int): Pair { - val c = get(index) - when { - Character.isJavaIdentifierStart(c) -> { - for (end in index + 1..length - 1) { - if (!Character.isJavaIdentifierPart(get(end))) { - return substring(index, end) to end - } - } - return substring(index, length) to length - } - c == '$' -> { - for (end in index + 1..length - 1) { - if (Character.isWhitespace(get(end))) { - return substring(index, end) to end - } - } - return substring(index, length) to length - } - c == '{' -> { - val end = indexOf('}', index + 1) - return substring(index + 1, end) to end + 1 - } - } - return "" to -1 -} - -fun String.parseSections(): MutableMap { - val sections = hashMapOf() - var currentLabel = "" - var currentSectionStart = 0 - var currentIndex = 0 - - while (currentIndex < length) { - if (get(currentIndex) == '$') { - val (label, index) = parseLabel(currentIndex + 1) - if (index != -1 && index < length() && get(index) == ':') { - // section starts, add previous section - val currentContent = substring(currentSectionStart, currentIndex).trim() - val section = DocumentationContentSection(currentLabel, currentContent.toRichString()) - sections.put(section.label, section) - - currentLabel = label - currentIndex = index + 1 - currentSectionStart = currentIndex - continue - } - } - currentIndex++ - - } - - val currentContent = substring(currentSectionStart, currentIndex).trim() - val section = DocumentationContentSection(currentLabel, currentContent.toRichString()) - sections.put(section.label, section) - return sections -} - -fun String.toRichString() : RichString { - val content = RichString() - for(index in indices) { - val ch = get(index) - when { - ch == '\\' -> continue - ch == '*' && index < length-1 && !get(index + 1).isWhitespace() -> ch - } - } - - content.addSlice(this, NormalStyle) - return content -} \ No newline at end of file diff --git a/src/Model/DocumentationModule.kt b/src/Model/DocumentationModule.kt index 78ebda04..6084ea5e 100644 --- a/src/Model/DocumentationModule.kt +++ b/src/Model/DocumentationModule.kt @@ -1,30 +1,11 @@ package org.jetbrains.dokka -import org.jetbrains.jet.lang.resolve.BindingContext -import org.jetbrains.jet.lang.descriptors.* -import org.jetbrains.jet.lang.resolve.name.FqName - -public class DocumentationModule(name: String, val module: ModuleDescriptor) : DocumentationNode(module, name, DocumentationContent.Empty, DocumentationNode.Kind.Module) { +public class DocumentationModule(name: String) : DocumentationNode(name, Content.Empty, DocumentationNode.Kind.Module) { fun merge(other: DocumentationModule): DocumentationModule { - val model = DocumentationModule(name, module) + val model = DocumentationModule(name) model.addAllReferencesFrom(other) model.addAllReferencesFrom(this) return model } } -fun BindingContext.createDocumentationModule(name: String, - module: ModuleDescriptor, - packages: Set, - options : DocumentationOptions = DocumentationOptions()): DocumentationModule { - val documentationModule = DocumentationModule(name, module) - val visitor = DocumentationNodeBuilder(this) - for (packageName in packages) { - val pkg = module.getPackage(packageName) - pkg!!.accept(DocumentationBuildingVisitor(this, options, visitor), documentationModule) - } - - // TODO: Uncomment for resolve verification - // checkResolveChildren(documentationModule) - return documentationModule -} diff --git a/src/Model/DocumentationNode.kt b/src/Model/DocumentationNode.kt index c96c383d..198e549b 100644 --- a/src/Model/DocumentationNode.kt +++ b/src/Model/DocumentationNode.kt @@ -1,12 +1,9 @@ package org.jetbrains.dokka -import org.jetbrains.jet.lang.descriptors.* import java.util.LinkedHashSet - -public open class DocumentationNode(val descriptor: DeclarationDescriptor, - val name: String, - val doc: DocumentationContent, +public open class DocumentationNode(val name: String, + val doc: Content, val kind: DocumentationNode.Kind) { private val references = LinkedHashSet() diff --git a/src/Model/DocumentationNodeBuilder.kt b/src/Model/DocumentationNodeBuilder.kt deleted file mode 100644 index f724c444..00000000 --- a/src/Model/DocumentationNodeBuilder.kt +++ /dev/null @@ -1,153 +0,0 @@ -package org.jetbrains.dokka - -import org.jetbrains.jet.lang.resolve.* -import org.jetbrains.jet.lang.descriptors.* -import org.jetbrains.jet.lang.descriptors.impl.* -import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns -import org.jetbrains.jet.lang.types.JetType - -class DocumentationNodeBuilder(val context: BindingContext) : DeclarationDescriptorVisitorEmptyBodies() { - - fun reference(from: DocumentationNode, to: DocumentationNode, kind: DocumentationReference.Kind) { - from.addReferenceTo(to, kind) - if (kind == DocumentationReference.Kind.Link) - to.addReferenceTo(from, DocumentationReference.Kind.Link) - else - to.addReferenceTo(from, DocumentationReference.Kind.Owner) - } - - fun addModality(descriptor: MemberDescriptor, data: DocumentationNode) { - val modifier = descriptor.getModality().name().toLowerCase() - val node = DocumentationNode(descriptor, modifier, DocumentationContent.Empty, DocumentationNode.Kind.Modifier) - reference(data, node, DocumentationReference.Kind.Detail) - } - - fun addVisibility(descriptor: MemberDescriptor, data: DocumentationNode) { - val modifier = descriptor.getVisibility().toString() - val node = DocumentationNode(descriptor, modifier, DocumentationContent.Empty, DocumentationNode.Kind.Modifier) - reference(data, node, DocumentationReference.Kind.Detail) - } - - fun addType(descriptor: DeclarationDescriptor, t: JetType?, data: DocumentationNode) { - if (t == null) - return - val typeConstructor = t.getConstructor() - val classifierDescriptor = typeConstructor.getDeclarationDescriptor() - val name = when (classifierDescriptor) { - is Named -> classifierDescriptor.getName().asString() - else -> "" - } - val node = DocumentationNode(descriptor, name, DocumentationContent.Empty, DocumentationNode.Kind.Type) - reference(data, node, DocumentationReference.Kind.Detail) - - for (param in t.getArguments()) - addType(descriptor, param.getType(), node) - } - - override fun visitDeclarationDescriptor(descriptor: DeclarationDescriptor?, data: DocumentationNode?): DocumentationNode? { - val doc = context.getDocumentation(descriptor!!) - val node = DocumentationNode(descriptor, descriptor.getName().asString(), doc, DocumentationNode.Kind.Unknown) - reference(data!!, node, DocumentationReference.Kind.Link) - return node - } - - override fun visitReceiverParameterDescriptor(descriptor: ReceiverParameterDescriptor?, data: DocumentationNode?): DocumentationNode? { - val node = DocumentationNode(descriptor!!, descriptor.getName().asString(), DocumentationContent.Empty, DocumentationNode.Kind.Receiver) - reference(data!!, node, DocumentationReference.Kind.Detail) - - addType(descriptor, descriptor.getType(), node) - - return node - } - - override fun visitValueParameterDescriptor(descriptor: ValueParameterDescriptor?, data: DocumentationNode?): DocumentationNode? { - val doc = context.getDocumentation(descriptor!!) - val node = DocumentationNode(descriptor, descriptor.getName().asString(), doc, DocumentationNode.Kind.Parameter) - reference(data!!, node, DocumentationReference.Kind.Detail) - - addType(descriptor, descriptor.getType(), node) - - return node - } - - override fun visitClassDescriptor(descriptor: ClassDescriptor?, data: DocumentationNode?): DocumentationNode? { - val doc = context.getDocumentation(descriptor!!) - val node = DocumentationNode(descriptor, descriptor.getName().asString(), doc, when (descriptor.getKind()) { - ClassKind.OBJECT -> DocumentationNode.Kind.Object - ClassKind.CLASS_OBJECT -> DocumentationNode.Kind.Object - ClassKind.TRAIT -> DocumentationNode.Kind.Interface - ClassKind.ENUM_CLASS -> DocumentationNode.Kind.Enum - ClassKind.ENUM_ENTRY -> DocumentationNode.Kind.EnumItem - else -> DocumentationNode.Kind.Class - }) - reference(data!!, node, DocumentationReference.Kind.Member) - addModality(descriptor, node) - addVisibility(descriptor, node) - return node - } - - override fun visitFunctionDescriptor(descriptor: FunctionDescriptor?, data: DocumentationNode?): DocumentationNode? { - val doc = context.getDocumentation(descriptor!!) - val node = DocumentationNode(descriptor, descriptor.getName().asString(), doc, DocumentationNode.Kind.Function) - reference(data!!, node, DocumentationReference.Kind.Member) - - addType(descriptor, descriptor.getReturnType(), node) - addModality(descriptor, node) - addVisibility(descriptor, node) - - return node - } - - override fun visitTypeParameterDescriptor(descriptor: TypeParameterDescriptor?, data: DocumentationNode?): DocumentationNode? { - val doc = context.getDocumentation(descriptor!!) - val node = DocumentationNode(descriptor, descriptor.getName().asString(), doc, DocumentationNode.Kind.TypeParameter) - reference(data!!, node, DocumentationReference.Kind.Detail) - val builtIns = KotlinBuiltIns.getInstance() - for (constraint in descriptor.getUpperBounds()) { - if (constraint == builtIns.getDefaultBound()) - continue - val constraintNode = DocumentationNode(descriptor, constraint.toString(), DocumentationContent.Empty, DocumentationNode.Kind.UpperBound) - reference(node, constraintNode, DocumentationReference.Kind.Detail) - } - for (constraint in descriptor.getLowerBounds()) { - if (builtIns.isNothing(constraint)) - continue - val constraintNode = DocumentationNode(descriptor, constraint.toString(), DocumentationContent.Empty, DocumentationNode.Kind.LowerBound) - reference(node, constraintNode, DocumentationReference.Kind.Detail) - } - return node - } - - override fun visitPropertyDescriptor(descriptor: PropertyDescriptor?, data: DocumentationNode?): DocumentationNode? { - val doc = context.getDocumentation(descriptor!!) - val node = DocumentationNode(descriptor, descriptor.getName().asString(), doc, DocumentationNode.Kind.Property) - reference(data!!, node, DocumentationReference.Kind.Member) - - addType(descriptor, descriptor.getType(), node) - addModality(descriptor, node) - addVisibility(descriptor, node) - return node - } - - override fun visitConstructorDescriptor(descriptor: ConstructorDescriptor?, data: DocumentationNode?): DocumentationNode? { - val doc = context.getDocumentation(descriptor!!) - val node = DocumentationNode(descriptor, descriptor.getName().asString(), doc, DocumentationNode.Kind.Constructor) - reference(data!!, node, DocumentationReference.Kind.Member) - - addVisibility(descriptor, node) - - return node - } - - override fun visitPackageViewDescriptor(descriptor: PackageViewDescriptor?, data: DocumentationNode?): DocumentationNode? { - val node = DocumentationNode(descriptor!!, descriptor.getFqName().asString(), DocumentationContent.Empty, DocumentationNode.Kind.Package) - reference(data!!, node, DocumentationReference.Kind.Member) - return node - } - - override fun visitPackageFragmentDescriptor(descriptor: PackageFragmentDescriptor?, data: DocumentationNode?): DocumentationNode? { - val node = DocumentationNode(descriptor!!, descriptor.fqName.asString(), DocumentationContent.Empty, DocumentationNode.Kind.Package) - reference(data!!, node, DocumentationReference.Kind.Member) - return node - } -} -- cgit