diff options
Diffstat (limited to 'src/Model')
-rw-r--r-- | src/Model/DocumentationBuilder.kt | 73 | ||||
-rw-r--r-- | src/Model/DocumentationBuildingVisitor.kt | 121 | ||||
-rw-r--r-- | src/Model/DocumentationModel.kt | 67 |
3 files changed, 261 insertions, 0 deletions
diff --git a/src/Model/DocumentationBuilder.kt b/src/Model/DocumentationBuilder.kt new file mode 100644 index 00000000..77f74eb2 --- /dev/null +++ b/src/Model/DocumentationBuilder.kt @@ -0,0 +1,73 @@ +package org.jetbrains.dokka + +import org.jetbrains.jet.lang.resolve.* +import org.jetbrains.jet.lang.psi.* +import org.jetbrains.jet.lang.descriptors.* +import org.jetbrains.jet.lang.descriptors.impl.* + +fun BindingContext.createDocumentation(file: JetFile): DocumentationModel { + val model = DocumentationModel() + val packageFragment = getPackageFragment(file) + if (packageFragment == null) throw IllegalArgumentException("File $file should have package fragment") + + val visitor = DocumentationBuilderVisitor(this) + visitDescriptor(packageFragment, model, visitor) + + return model +} + +class DocumentationBuilderVisitor(val context: BindingContext) : DeclarationDescriptorVisitorEmptyBodies<DocumentationNode, DocumentationNode>() { + + override fun visitDeclarationDescriptor(descriptor: DeclarationDescriptor?, data: DocumentationNode?): DocumentationNode? { + val doc = context.getDocumentation(descriptor!!).extractText() + val node = DocumentationNode(descriptor.getName().asString(), doc, DocumentationNodeKind.Unknown) + data?.addReferenceTo(node, DocumentationReferenceKind.Member) + return node + } + + override fun visitValueParameterDescriptor(descriptor: ValueParameterDescriptor?, data: DocumentationNode?): DocumentationNode? { + val doc = context.getDocumentation(descriptor!!).extractText() + val node = DocumentationNode(descriptor.getName().asString(), doc, DocumentationNodeKind.Parameter) + data?.addReferenceTo(node, DocumentationReferenceKind.Detail) + return node + } + + override fun visitClassDescriptor(descriptor: ClassDescriptor?, data: DocumentationNode?): DocumentationNode? { + val doc = context.getDocumentation(descriptor!!).extractText() + val node = DocumentationNode(descriptor.getName().asString(), doc, + when (descriptor.getKind()) { + ClassKind.OBJECT -> DocumentationNodeKind.Object + else -> DocumentationNodeKind.Class + } + ) + data?.addReferenceTo(node, DocumentationReferenceKind.Member) + return node + } + + override fun visitFunctionDescriptor(descriptor: FunctionDescriptor?, data: DocumentationNode?): DocumentationNode? { + val doc = context.getDocumentation(descriptor!!).extractText() + val node = DocumentationNode(descriptor.getName().asString(), doc, DocumentationNodeKind.Function) + data?.addReferenceTo(node, DocumentationReferenceKind.Member) + return node + } + + override fun visitPropertyDescriptor(descriptor: PropertyDescriptor?, data: DocumentationNode?): DocumentationNode? { + val doc = context.getDocumentation(descriptor!!).extractText() + val node = DocumentationNode(descriptor.getName().asString(), doc, DocumentationNodeKind.Property) + data?.addReferenceTo(node, DocumentationReferenceKind.Member) + return node + } + + override fun visitConstructorDescriptor(descriptor: ConstructorDescriptor?, data: DocumentationNode?): DocumentationNode? { + val doc = context.getDocumentation(descriptor!!).extractText() + val node = DocumentationNode(descriptor.getName().asString(), doc, DocumentationNodeKind.Constructor) + data?.addReferenceTo(node, DocumentationReferenceKind.Member) + return node + } + + override fun visitPackageFragmentDescriptor(descriptor: PackageFragmentDescriptor?, data: DocumentationNode?): DocumentationNode? { + val node = DocumentationNode(descriptor!!.fqName.asString(), "", DocumentationNodeKind.Package) + data?.addReferenceTo(node, DocumentationReferenceKind.Member) + return node + } +} diff --git a/src/Model/DocumentationBuildingVisitor.kt b/src/Model/DocumentationBuildingVisitor.kt new file mode 100644 index 00000000..e7b3fc09 --- /dev/null +++ b/src/Model/DocumentationBuildingVisitor.kt @@ -0,0 +1,121 @@ +package org.jetbrains.dokka + +import org.jetbrains.jet.lang.descriptors.* +import org.jetbrains.jet.lang.resolve.name.FqName + +class DocumentationBuildingVisitor(private val worker: DeclarationDescriptorVisitor<DocumentationNode, DocumentationNode>) +: DeclarationDescriptorVisitor<DocumentationNode, DocumentationNode> { + + private fun visitChildren(descriptors: Collection<DeclarationDescriptor>, data: DocumentationNode) { + for (descriptor in descriptors) { + if (descriptor.isUserCode()) + descriptor.accept(this, data) + } + } + + private fun visitChild(descriptor: DeclarationDescriptor?, data: DocumentationNode) { + if (descriptor != null && descriptor.isUserCode()) + 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) + } + val members = descriptor.getDefaultType().getMemberScope().getAllDescriptors().filter { + it !is CallableMemberDescriptor || it.isUserCode() + } + visitChildren(members, 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(constructorDescriptor: ConstructorDescriptor?, data: DocumentationNode?): DocumentationNode? { + val node = visitFunctionDescriptor(constructorDescriptor, data) + return node + } + + public override fun visitScriptDescriptor(scriptDescriptor: ScriptDescriptor?, data: DocumentationNode?): DocumentationNode? { + val node = visitClassDescriptor(scriptDescriptor!!.getClassDescriptor(), 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 + } +} + +public fun visitDescriptor(descriptor: DeclarationDescriptor, data: DocumentationNode, visitor: DeclarationDescriptorVisitor<DocumentationNode, DocumentationNode>): DocumentationNode { + return descriptor.accept(DocumentationBuildingVisitor(visitor), data) +} diff --git a/src/Model/DocumentationModel.kt b/src/Model/DocumentationModel.kt new file mode 100644 index 00000000..0113eb18 --- /dev/null +++ b/src/Model/DocumentationModel.kt @@ -0,0 +1,67 @@ +package org.jetbrains.dokka + +import org.jetbrains.jet.lang.resolve.BindingContext +import org.jetbrains.jet.lang.psi.JetFile + +public enum class DocumentationNodeKind { + Unknown + + Package + Class + Object + Constructor + Function + Property + Parameter + TypeParameter + Exception + + Page + Model +} + +public enum class DocumentationReferenceKind { + Member + Detail + Owner + Link + Override +} + +public open class DocumentationNode(val name: String, val doc: String, val kind: DocumentationNodeKind) { + private val references = arrayListOf<DocumentationReference>() + + public val owner: DocumentationNode + get() = references(DocumentationReferenceKind.Owner).single().to + public val details: List<DocumentationNode> + get() = references(DocumentationReferenceKind.Detail).map { it.to } + public val members: List<DocumentationNode> + get() = references(DocumentationReferenceKind.Member).map { it.to } + public val links: List<DocumentationNode> + get() = references(DocumentationReferenceKind.Link).map { it.to } + + // TODO: Should we allow node mutation? Model merge will copy by ref, so references are transparent, which could nice + public fun addReferenceTo(to: DocumentationNode, kind: DocumentationReferenceKind) { + references.add(DocumentationReference(this, to, kind)) + } + + public fun addAllReferencesFrom(other: DocumentationNode) { + references.addAll(other.references) + } + + public fun references(kind: DocumentationReferenceKind): List<DocumentationReference> = references.filter { it.kind == kind } +} + +public class DocumentationModel : DocumentationNode("model", "", DocumentationNodeKind.Model) { + fun merge(other: DocumentationModel): DocumentationModel { + val model = DocumentationModel() + model.addAllReferencesFrom(other) + model.addAllReferencesFrom(this) + return model + } + + public val nodes: List<DocumentationNode> + get() = members +} + +public data class DocumentationReference(val from: DocumentationNode, val to: DocumentationNode, val kind: DocumentationReferenceKind) |