aboutsummaryrefslogtreecommitdiff
path: root/javadoc/src/main
diff options
context:
space:
mode:
authorSergey Mashkov <sergey.mashkov@jetbrains.com>2015-07-28 14:15:55 +0300
committerDmitry Jemerov <yole@jetbrains.com>2015-10-29 12:34:00 +0100
commitff77b8e0ad0b5089e940227dfdd94ba21cfc6bd8 (patch)
tree1710b631ba4d24e685a109ca25b46c718b30cfa6 /javadoc/src/main
parent69623756c6a28d1ba70edcdfd6e02c686ed502e7 (diff)
downloaddokka-ff77b8e0ad0b5089e940227dfdd94ba21cfc6bd8.tar.gz
dokka-ff77b8e0ad0b5089e940227dfdd94ba21cfc6bd8.tar.bz2
dokka-ff77b8e0ad0b5089e940227dfdd94ba21cfc6bd8.zip
Initial javadoc generation module
Diffstat (limited to 'javadoc/src/main')
-rw-r--r--javadoc/src/main/kotlin/docbase.kt500
-rw-r--r--javadoc/src/main/kotlin/main.kt24
-rw-r--r--javadoc/src/main/kotlin/reporter.kt30
-rw-r--r--javadoc/src/main/kotlin/source-position.kt18
-rw-r--r--javadoc/src/main/kotlin/tags.kt180
-rw-r--r--javadoc/src/main/kotlin/utils.kt10
6 files changed, 762 insertions, 0 deletions
diff --git a/javadoc/src/main/kotlin/docbase.kt b/javadoc/src/main/kotlin/docbase.kt
new file mode 100644
index 00000000..fe66a672
--- /dev/null
+++ b/javadoc/src/main/kotlin/docbase.kt
@@ -0,0 +1,500 @@
+package org.jetbrains.dokka.javadoc
+
+import com.sun.javadoc.*
+import org.jetbrains.dokka.*
+import java.lang.reflect.Modifier
+import java.util.Collections
+import java.util.HashSet
+
+open class DocumentationNodeBareAdapter(val docNode: DocumentationNode) : Doc {
+ private var rawCommentText_ = rawCommentText
+
+ override fun name(): String = docNode.name
+ override fun position(): SourcePosition? = SourcePositionAdapter(docNode)
+
+ override fun inlineTags(): Array<out Tag>? = emptyArray()
+ override fun firstSentenceTags(): Array<out Tag>? = emptyArray()
+ override fun tags(): Array<out Tag> = emptyArray()
+ override fun tags(tagname: String?): Array<out Tag>? = tags().filter { it.kind() == tagname || it.kind() == "@$tagname" }.toTypedArray()
+ override fun seeTags(): Array<out SeeTag>? = tags().filterIsInstance<SeeTag>().toTypedArray()
+ override fun commentText(): String = ""
+
+ override fun setRawCommentText(rawDocumentation: String?) {
+ rawCommentText_ = rawDocumentation ?: ""
+ }
+
+ override fun getRawCommentText(): String = rawCommentText_
+
+ override fun isError(): Boolean = false
+ override fun isException(): Boolean = docNode.kind == DocumentationNode.Kind.Exception
+ override fun isEnumConstant(): Boolean = docNode.kind == DocumentationNode.Kind.EnumItem
+ override fun isEnum(): Boolean = docNode.kind == DocumentationNode.Kind.Enum
+ override fun isMethod(): Boolean = docNode.kind == DocumentationNode.Kind.Function
+ override fun isInterface(): Boolean = docNode.kind == DocumentationNode.Kind.Interface
+ override fun isField(): Boolean = docNode.kind == DocumentationNode.Kind.Property
+ override fun isClass(): Boolean = docNode.kind == DocumentationNode.Kind.Class
+ override fun isAnnotationType(): Boolean = docNode.kind == DocumentationNode.Kind.AnnotationClass
+ override fun isConstructor(): Boolean = docNode.kind == DocumentationNode.Kind.Constructor
+ override fun isOrdinaryClass(): Boolean = docNode.kind == DocumentationNode.Kind.Class
+ override fun isAnnotationTypeElement(): Boolean = docNode.kind == DocumentationNode.Kind.Annotation
+
+ override fun compareTo(other: Any?): Int = when (other) {
+ !is DocumentationNodeAdapter -> 1
+ else -> docNode.name.compareTo(other.docNode.name)
+ }
+
+ override fun equals(other: Any?): Boolean = docNode.qualifiedName == (other as? DocumentationNodeAdapter)?.docNode?.qualifiedName
+ override fun hashCode(): Int = docNode.name.hashCode()
+
+ override fun isIncluded(): Boolean = docNode.kind != DocumentationNode.Kind.ExternalClass
+}
+
+
+// TODO think of source position instead of null
+// TODO tags
+open class DocumentationNodeAdapter(val module: ModuleNodeAdapter, docNode: DocumentationNode) : DocumentationNodeBareAdapter(docNode) {
+ override fun inlineTags(): Array<out Tag> = buildInlineTags(module, this, docNode.content).toTypedArray()
+ override fun firstSentenceTags(): Array<out Tag> = buildInlineTags(module, this, docNode.summary).toTypedArray()
+ override fun tags(): Array<out Tag> = (buildInlineTags(module, this, docNode.content) + docNode.content.sections.flatMap {
+ when (it.tag) {
+ "See Also" -> buildInlineTags(module, this, it)
+ else -> emptyList<Tag>()
+ }
+ }).toTypedArray()
+}
+
+private val allClassKinds = setOf(DocumentationNode.Kind.Class, DocumentationNode.Kind.Enum, DocumentationNode.Kind.Interface, DocumentationNode.Kind.Object, DocumentationNode.Kind.Exception)
+
+class PackageAdapter(module: ModuleNodeAdapter, val node: DocumentationNode) : DocumentationNodeAdapter(module, node), PackageDoc {
+ private val allClasses = node.members.filter { it.kind in allClassKinds }.toMap { it.name }
+ private val packageFacade = PackageFacadeAdapter(module, node)
+
+ override fun findClass(className: String?): ClassDoc? =
+ allClasses.get(className)?.let { ClassDocumentationNodeAdapter(module, it) }
+ ?: if (packageFacade.name() == className) packageFacade else null
+
+ override fun annotationTypes(): Array<out AnnotationTypeDoc> = emptyArray()
+ override fun annotations(): Array<out AnnotationDesc> = node.members(DocumentationNode.Kind.AnnotationClass).map { AnnotationDescAdapter(module, it) }.toTypedArray()
+ override fun exceptions(): Array<out ClassDoc> = node.members(DocumentationNode.Kind.Exception).map { ClassDocumentationNodeAdapter(module, it) }.toTypedArray()
+ override fun ordinaryClasses(): Array<out ClassDoc> = (node.members(DocumentationNode.Kind.Class).map { ClassDocumentationNodeAdapter(module, it) } + packageFacade).toTypedArray()
+ override fun interfaces(): Array<out ClassDoc> = node.members(DocumentationNode.Kind.Interface).map { ClassDocumentationNodeAdapter(module, it) }.toTypedArray()
+ override fun errors(): Array<out ClassDoc> = emptyArray()
+ override fun enums(): Array<out ClassDoc> = node.members(DocumentationNode.Kind.Enum).map { ClassDocumentationNodeAdapter(module, it) }.toTypedArray()
+ override fun allClasses(filter: Boolean): Array<out ClassDoc> = (allClasses.values().map { ClassDocumentationNodeAdapter(module, it) } + packageFacade).toTypedArray()
+ override fun allClasses(): Array<out ClassDoc> = allClasses(true)
+
+ override fun isIncluded(): Boolean = node.name in module.allPackages
+}
+
+class AnnotationTypeDocAdapter(module: ModuleNodeAdapter, node: DocumentationNode) : ClassDocumentationNodeAdapter(module, node), AnnotationTypeDoc {
+ override fun elements(): Array<out AnnotationTypeElementDoc>? = emptyArray() // TODO
+}
+
+class AnnotationDescAdapter(val module: ModuleNodeAdapter, val node: DocumentationNode) : AnnotationDesc {
+ override fun annotationType(): AnnotationTypeDoc? = AnnotationTypeDocAdapter(module, node) // TODO ?????
+ override fun isSynthesized(): Boolean = false
+ override fun elementValues(): Array<out AnnotationDesc.ElementValuePair>? = emptyArray() // TODO
+}
+
+class ProgramElementAdapter(module: ModuleNodeAdapter, val node: DocumentationNode) : DocumentationNodeAdapter(module, node), ProgramElementDoc {
+ override fun isPublic(): Boolean = true
+ override fun isPackagePrivate(): Boolean = false
+ override fun isStatic(): Boolean = node.owner?.kind in listOf(DocumentationNode.Kind.Package, DocumentationNode.Kind.ExternalClass)
+ override fun modifierSpecifier(): Int = Modifier.PUBLIC + if (isStatic) Modifier.STATIC else 0
+ override fun qualifiedName(): String? = node.qualifiedName
+ override fun annotations(): Array<out AnnotationDesc>? = node.annotations.map { AnnotationDescAdapter(module, it) }.toTypedArray()
+ override fun modifiers(): String? = "public ${if (isStatic) "static" else ""}".trim()
+ override fun isProtected(): Boolean = false
+
+ override fun isFinal(): Boolean = node.details(DocumentationNode.Kind.Modifier).any { it.name == "final" }
+
+ override fun containingPackage(): PackageDoc? {
+ var owner: DocumentationNode? = node
+ while (owner != null) {
+ if (owner.kind == DocumentationNode.Kind.Package) {
+ return PackageAdapter(module, owner)
+ }
+ owner = owner.owner
+ }
+
+ return null
+ }
+
+ override fun containingClass(): ClassDoc? {
+ var owner = node.owner
+ while (owner != null) {
+ when (owner.kind) {
+ DocumentationNode.Kind.Class -> return ClassDocumentationNodeAdapter(module, owner)
+ DocumentationNode.Kind.Package -> return PackageFacadeAdapter(module, owner)
+ else -> owner = owner.owner
+ }
+ }
+
+ return null
+ }
+
+ override fun isPrivate(): Boolean = false
+ override fun isIncluded(): Boolean = containingPackage()?.isIncluded ?: false && containingClass()?.let { it.isIncluded } ?: true
+}
+
+public fun DocumentationNode.getArrayElementType(): DocumentationNode? = when (name) {
+ "Array" -> details(DocumentationNode.Kind.Type).singleOrNull()?.let { et -> et.getArrayElementType() ?: et } ?: DocumentationNode("Object", content, DocumentationNode.Kind.ExternalClass)
+ "IntArray", "LongArray", "ShortArray", "ByteArray", "CharArray", "DoubleArray", "FloatArray", "BooleanArray" -> DocumentationNode(name.removeSuffix("Array").toLowerCase(), content, DocumentationNode.Kind.Type)
+ else -> null
+}
+
+fun DocumentationNode.getArrayDimension(): Int = when (name) {
+ "Array" -> 1 + (details(DocumentationNode.Kind.Type).singleOrNull()?.getArrayDimension() ?: 0)
+ "IntArray", "LongArray", "ShortArray", "ByteArray", "CharArray", "DoubleArray", "FloatArray", "BooleanArray" -> 1
+ else -> 0
+}
+
+//fun DocumentationNode.convertNativeType(): DocumentationNode = when (name) {
+// "Unit" -> DocumentationNode("void", content, kind)
+// "Int" -> DocumentationNode("int", content, kind)
+//}
+
+open class TypeAdapter(val module: ModuleNodeAdapter, val node: DocumentationNode) : Type {
+ override fun qualifiedTypeName(): String = node.getArrayElementType()?.qualifiedName ?: node.qualifiedName
+ override fun typeName(): String = node.getArrayElementType()?.name ?: node.name
+ override fun simpleTypeName(): String = typeName() // TODO difference typeName() vs simpleTypeName()
+
+ override fun dimension(): String = Collections.nCopies(node.getArrayDimension(), "[]").joinToString("")
+ override fun isPrimitive(): Boolean = node.name in setOf("Int", "Long", "Short", "Byte", "Char", "Double", "Float", "Boolean", "Unit")
+ override fun asClassDoc(): ClassDoc? = if (isPrimitive) null else
+ elementType?.asClassDoc() ?:
+ when (node.kind) {
+ DocumentationNode.Kind.Class,
+ DocumentationNode.Kind.ExternalClass,
+ DocumentationNode.Kind.Interface,
+ DocumentationNode.Kind.Object,
+ DocumentationNode.Kind.Exception,
+ DocumentationNode.Kind.Enum -> ClassDocumentationNodeAdapter(module, node)
+
+ else -> when {
+ node.links.isNotEmpty() -> TypeAdapter(module, node.links.first()).asClassDoc()
+ else -> ClassDocumentationNodeAdapter(module, node) // TODO ?
+ }
+ }
+
+ override fun asTypeVariable(): TypeVariable? = if (node.kind == DocumentationNode.Kind.TypeParameter) TypeVariableAdapter(module, node) else null
+ override fun asParameterizedType(): ParameterizedType? =
+ if (node.details(DocumentationNode.Kind.Type).isNotEmpty()) ParameterizedTypeAdapter(module, node)
+ else null // TODO it should ignore dimensions
+
+ override fun asAnnotationTypeDoc(): AnnotationTypeDoc? = if (node.kind == DocumentationNode.Kind.AnnotationClass) AnnotationTypeDocAdapter(module, node) else null
+ override fun asAnnotatedType(): AnnotatedType? = if (node.annotations.isNotEmpty()) AnnotatedTypeAdapter(module, node) else null
+ override fun getElementType(): Type? = node.getArrayElementType()?.let { et -> TypeAdapter(module, et) }
+ override fun asWildcardType(): WildcardType? = null
+
+ override fun toString(): String = qualifiedTypeName() + dimension()
+ override fun hashCode(): Int = node.name.hashCode()
+ override fun equals(other: Any?): Boolean = other is TypeAdapter && toString() == other.toString()
+}
+
+class AnnotatedTypeAdapter(module: ModuleNodeAdapter, node: DocumentationNode) : TypeAdapter(module, node), AnnotatedType {
+ override fun underlyingType(): Type? = this
+ override fun annotations(): Array<out AnnotationDesc> = node.annotations.map { AnnotationDescAdapter(module, it) }.toTypedArray()
+}
+
+class WildcardTypeAdapter(module: ModuleNodeAdapter, node: DocumentationNode) : TypeAdapter(module, node), WildcardType {
+ override fun extendsBounds(): Array<out Type> = node.details(DocumentationNode.Kind.UpperBound).map { TypeAdapter(module, it) }.toTypedArray()
+ override fun superBounds(): Array<out Type> = node.details(DocumentationNode.Kind.LowerBound).map { TypeAdapter(module, it) }.toTypedArray()
+}
+
+class TypeVariableAdapter(module: ModuleNodeAdapter, node: DocumentationNode) : TypeAdapter(module, node), TypeVariable {
+ override fun owner(): ProgramElementDoc = node.owner!!.let<DocumentationNode, ProgramElementDoc> { owner ->
+ when (owner.kind) {
+ DocumentationNode.Kind.Function,
+ DocumentationNode.Kind.Constructor -> ExecutableMemberAdapter(module, owner)
+
+ DocumentationNode.Kind.Class,
+ DocumentationNode.Kind.Interface,
+ DocumentationNode.Kind.Enum -> ClassDocumentationNodeAdapter(module, owner)
+
+ else -> ProgramElementAdapter(module, node.owner!!)
+ }
+ }
+
+ override fun bounds(): Array<out Type>? = node.details(DocumentationNode.Kind.UpperBound).map { TypeAdapter(module, it) }.toTypedArray()
+ override fun annotations(): Array<out AnnotationDesc>? = node.members(DocumentationNode.Kind.Annotation).map { AnnotationDescAdapter(module, it) }.toTypedArray()
+
+ override fun qualifiedTypeName(): String = node.name
+ override fun simpleTypeName(): String = node.name
+ override fun typeName(): String = node.name
+
+ override fun hashCode(): Int = node.name.hashCode()
+ override fun equals(other: Any?): Boolean = other is Type && other.typeName() == typeName() && other.asTypeVariable()?.owner() == owner()
+
+ override fun asTypeVariable(): TypeVariableAdapter = this
+ // override fun asClassDoc(): ClassDoc? = null
+}
+
+class ParameterizedTypeAdapter(module: ModuleNodeAdapter, node: DocumentationNode) : TypeAdapter(module, node), ParameterizedType {
+ override fun typeArguments(): Array<out Type> = node.details(DocumentationNode.Kind.Type).map { TypeVariableAdapter(module, it) }.toTypedArray()
+ override fun superclassType(): Type? =
+ node.lookupSuperClasses(module)
+ .firstOrNull { it.kind == DocumentationNode.Kind.Class || it.kind == DocumentationNode.Kind.ExternalClass }
+ ?.let { ClassDocumentationNodeAdapter(module, it) }
+
+ override fun interfaceTypes(): Array<out Type> =
+ node.lookupSuperClasses(module)
+ .filter { it.kind == DocumentationNode.Kind.Interface }
+ .map { ClassDocumentationNodeAdapter(module, it) }
+ .toTypedArray()
+
+ override fun containingType(): Type? = when (node.owner?.kind) {
+ DocumentationNode.Kind.Package -> null
+ DocumentationNode.Kind.Class,
+ DocumentationNode.Kind.Interface,
+ DocumentationNode.Kind.Object,
+ DocumentationNode.Kind.Enum -> ClassDocumentationNodeAdapter(module, node.owner!!)
+
+ else -> null
+ }
+}
+
+class ParameterAdapter(module: ModuleNodeAdapter, val node: DocumentationNode) : DocumentationNodeAdapter(module, node), Parameter {
+ override fun typeName(): String? = JavaLanguageService().renderType(node.detail(DocumentationNode.Kind.Type))
+ override fun type(): Type? = TypeAdapter(module, node.detail(DocumentationNode.Kind.Type))
+ override fun annotations(): Array<out AnnotationDesc>? = node.details(DocumentationNode.Kind.Annotation).map { AnnotationDescAdapter(module, it) }.toTypedArray()
+}
+
+class ReceiverParameterAdapter(module: ModuleNodeAdapter, val receiverType: DocumentationNode) : DocumentationNodeAdapter(module, receiverType), Parameter {
+ override fun typeName(): String? = receiverType.name
+ override fun type(): Type? = TypeAdapter(module, receiverType)
+ override fun annotations(): Array<out AnnotationDesc> = emptyArray()
+ override fun name(): String = "receiver"
+}
+
+fun classOf(fqName: String, kind: DocumentationNode.Kind = DocumentationNode.Kind.Class) = DocumentationNode(fqName.substringAfterLast(".", fqName), Content.Empty, kind).let { node ->
+ val pkg = fqName.substringBeforeLast(".", "")
+ if (pkg.isNotEmpty()) {
+ node.append(DocumentationNode(pkg, Content.Empty, DocumentationNode.Kind.Package), DocumentationReference.Kind.Owner)
+ }
+
+ node
+}
+
+open class ExecutableMemberAdapter(module: ModuleNodeAdapter, val node: DocumentationNode) : DocumentationNodeAdapter(module, node), ProgramElementDoc by ProgramElementAdapter(module, node), ExecutableMemberDoc {
+
+ override fun isSynthetic(): Boolean = false
+ override fun isNative(): Boolean = node.annotations.any { it.name == "native" }
+
+ override fun thrownExceptions(): Array<out ClassDoc> = emptyArray() // TODO
+ override fun throwsTags(): Array<out ThrowsTag> =
+ node.content.sections
+ .filter { it.tag == "Exceptions" }
+ .map { it.subjectName }
+ .filterNotNull()
+ .map { ThrowsTagAdapter(this, ClassDocumentationNodeAdapter(module, classOf(it, DocumentationNode.Kind.Exception))) }
+ .toTypedArray()
+
+ override fun isVarArgs(): Boolean = node.details(DocumentationNode.Kind.Parameter).any { false } // TODO
+
+ override fun isSynchronized(): Boolean = node.annotations.any { it.name == "synchronized" }
+ override fun paramTags(): Array<out ParamTag> = node.details(DocumentationNode.Kind.Parameter).filter { it.content.summary !is ContentEmpty || it.content.description !is ContentEmpty || it.content.sections.isNotEmpty() }.map {
+ ParamTagAdapter(module, this, it.name, false, it.content.children)
+ }.toTypedArray()
+
+ override fun thrownExceptionTypes(): Array<out Type> = emptyArray()
+ override fun receiverType(): Type? = receiverNode()?.let { receiver -> TypeAdapter(module, receiver) }
+ override fun flatSignature(): String = node.details(DocumentationNode.Kind.Parameter).map { JavaLanguageService().renderType(it) }.joinToString(", ", "(", ")")
+ override fun signature(): String = node.details(DocumentationNode.Kind.Parameter).map { JavaLanguageService().renderType(it) }.joinToString(", ", "(", ")") // TODO it should be FQ types
+
+ override fun parameters(): Array<out Parameter> =
+ ((receiverNode()?.let { receiver -> listOf<Parameter>(ReceiverParameterAdapter(module, receiver)) } ?: emptyList())
+ + node.details(DocumentationNode.Kind.Parameter).map { ParameterAdapter(module, it) }
+ ).toTypedArray()
+
+ override fun typeParameters(): Array<out TypeVariable> = node.details(DocumentationNode.Kind.TypeParameter).map { TypeVariableAdapter(module, it) }.toTypedArray()
+
+ override fun typeParamTags(): Array<out ParamTag> = node.details(DocumentationNode.Kind.TypeParameter).filter { it.content.summary !is ContentEmpty || it.content.description !is ContentEmpty || it.content.sections.isNotEmpty() }.map {
+ ParamTagAdapter(module, this, it.name, true, it.content.children)
+ }.toTypedArray()
+
+ private fun receiverNode() = node.details(DocumentationNode.Kind.Receiver).let { receivers ->
+ when {
+ receivers.isNotEmpty() -> receivers.single().detail(DocumentationNode.Kind.Type)
+ else -> null
+ }
+ }
+}
+
+class ConstructorAdapter(module: ModuleNodeAdapter, node: DocumentationNode) : ExecutableMemberAdapter(module, node), ConstructorDoc {
+ override fun name(): String = node.owner?.name ?: throw IllegalStateException("No owner for $node")
+}
+
+class MethodAdapter(module: ModuleNodeAdapter, val node: DocumentationNode) : DocumentationNodeAdapter(module, node), ExecutableMemberDoc by ExecutableMemberAdapter(module, node), MethodDoc {
+ override fun overrides(meth: MethodDoc?): Boolean = false // TODO
+
+ override fun overriddenType(): Type? = node.overrides.firstOrNull()?.owner?.let { owner -> TypeAdapter(module, owner) }
+
+ override fun overriddenMethod(): MethodDoc? = node.overrides.map { MethodAdapter(module, it) }.firstOrNull()
+ override fun overriddenClass(): ClassDoc? = overriddenMethod()?.containingClass()
+
+ override fun isAbstract(): Boolean = false // TODO
+
+ override fun isDefault(): Boolean = false
+
+ override fun returnType(): Type = TypeAdapter(module, node.detail(DocumentationNode.Kind.Type))
+}
+
+class FieldAdapter(module: ModuleNodeAdapter, val node: DocumentationNode) : DocumentationNodeAdapter(module, node), ProgramElementDoc by ProgramElementAdapter(module, node), FieldDoc {
+ override fun isSynthetic(): Boolean = false
+
+ override fun constantValueExpression(): String? = null // TODO
+ override fun constantValue(): Any? = null
+
+ override fun type(): Type = TypeAdapter(module, node.detail(DocumentationNode.Kind.Type))
+ override fun isTransient(): Boolean = false // TODO
+ override fun serialFieldTags(): Array<out SerialFieldTag> = emptyArray()
+
+ override fun isVolatile(): Boolean = false // TODO
+}
+
+open class ClassDocumentationNodeAdapter(module: ModuleNodeAdapter, val classNode: DocumentationNode) : DocumentationNodeAdapter(module, classNode), Type by TypeAdapter(module, classNode), ProgramElementDoc by ProgramElementAdapter(module, classNode), ClassDoc {
+ override fun constructors(filter: Boolean): Array<out ConstructorDoc> = classNode.members(DocumentationNode.Kind.Constructor).map { ConstructorAdapter(module, it) }.toTypedArray()
+ override fun constructors(): Array<out ConstructorDoc> = constructors(true)
+ override fun importedPackages(): Array<out PackageDoc> = emptyArray()
+ override fun importedClasses(): Array<out ClassDoc>? = emptyArray()
+ override fun typeParameters(): Array<out TypeVariable> = classNode.details(DocumentationNode.Kind.TypeParameter).map { TypeVariableAdapter(module, it) }.toTypedArray()
+ override fun asTypeVariable(): TypeVariable? = if (classNode.kind == DocumentationNode.Kind.Class) TypeVariableAdapter(module, classNode) else null
+ override fun isExternalizable(): Boolean = interfaces().any { it.qualifiedName() == "java.io.Externalizable" }
+ override fun definesSerializableFields(): Boolean = false
+ override fun methods(filter: Boolean): Array<out MethodDoc> = classNode.members(DocumentationNode.Kind.Function).map { MethodAdapter(module, it) }.toTypedArray() // TODO include get/set methods
+ override fun methods(): Array<out MethodDoc> = methods(true)
+ override fun enumConstants(): Array<out FieldDoc>? = classNode.members(DocumentationNode.Kind.EnumItem).map { FieldAdapter(module, it) }.toTypedArray()
+ override fun isAbstract(): Boolean = classNode.details(DocumentationNode.Kind.Modifier).any { it.name == "abstract" }
+ override fun interfaceTypes(): Array<out Type> = classNode.lookupSuperClasses(module)
+ .filter { it.kind == DocumentationNode.Kind.Interface }
+ .map { ClassDocumentationNodeAdapter(module, it) }
+ .toTypedArray()
+
+ override fun interfaces(): Array<out ClassDoc> = classNode.lookupSuperClasses(module)
+ .filter { it.kind == DocumentationNode.Kind.Interface }
+ .map { ClassDocumentationNodeAdapter(module, it) }
+ .toTypedArray()
+
+ override fun typeParamTags(): Array<out ParamTag> = (classNode.details(DocumentationNode.Kind.TypeParameter).filter { it.content.summary !is ContentEmpty || it.content.description !is ContentEmpty || it.content.sections.isNotEmpty() }.map {
+ ParamTagAdapter(module, this, it.name, true, it.content.children)
+ } + classNode.content.sections.filter { it.subjectName in typeParameters().map { it.simpleTypeName() } }.map {
+ ParamTagAdapter(module, this, it.subjectName ?: "?", true, it.children)
+ }).toTypedArray()
+
+ override fun fields(): Array<out FieldDoc> = emptyArray()
+ override fun fields(filter: Boolean): Array<out FieldDoc> = emptyArray()
+
+ override fun findClass(className: String?): ClassDoc? = null // TODO !!!
+ override fun serializableFields(): Array<out FieldDoc> = emptyArray()
+ override fun superclassType(): Type? = classNode.lookupSuperClasses(module).singleOrNull { it.kind == DocumentationNode.Kind.Class }?.let { ClassDocumentationNodeAdapter(module, it) }
+ override fun serializationMethods(): Array<out MethodDoc> = emptyArray() // TODO
+ override fun superclass(): ClassDoc? = classNode.lookupSuperClasses(module).singleOrNull { it.kind == DocumentationNode.Kind.Class }?.let { ClassDocumentationNodeAdapter(module, it) }
+ override fun isSerializable(): Boolean = false // TODO
+ override fun subclassOf(cd: ClassDoc?): Boolean {
+ if (cd == null) {
+ return false
+ }
+
+ val expectedFQName = cd.qualifiedName()
+ val types = arrayListOf(classNode)
+ val visitedTypes = HashSet<String>()
+
+ while (types.isNotEmpty()) {
+ val type = types.remove(types.lastIndex)
+ val fqName = type.qualifiedName
+
+ if (expectedFQName == fqName) {
+ return true
+ }
+
+ visitedTypes.add(fqName)
+ types.addAll(type.details(DocumentationNode.Kind.Supertype).filter { it.qualifiedName !in visitedTypes })
+ }
+
+ return false
+ }
+
+ override fun innerClasses(): Array<out ClassDoc> = classNode.members(DocumentationNode.Kind.Class).map { ClassDocumentationNodeAdapter(module, it) }.toTypedArray()
+ override fun innerClasses(filter: Boolean): Array<out ClassDoc> = innerClasses()
+}
+
+class PackageFacadeAdapter(val module: ModuleNodeAdapter, val packageNode: DocumentationNode) : ProgramElementDoc by ProgramElementAdapter(module, packageNode), ClassDoc {
+ override fun simpleTypeName(): String = packageNode.name.substringAfterLast(".", packageNode.name).capitalize() + "Package"
+ override fun typeName(): String = simpleTypeName()
+ override fun qualifiedTypeName(): String = packageNode.name.split(".").let { parts -> parts.take(parts.size() - 1) + parts.takeLast(1).map { it.capitalize() + "Package" } }.joinToString(".")
+ override fun qualifiedName(): String = qualifiedTypeName()
+ override fun name(): String = simpleTypeName()
+
+ override fun isPrimitive(): Boolean = false
+ override fun dimension(): String = ""
+ override fun getElementType(): Type? = null
+ override fun asParameterizedType(): ParameterizedType? = null
+ override fun asClassDoc(): ClassDoc = this
+ override fun asAnnotationTypeDoc(): AnnotationTypeDoc? = null
+ override fun asAnnotatedType(): AnnotatedType? = null
+ override fun asWildcardType(): WildcardType? = null
+ override fun asTypeVariable(): TypeVariable? = null
+ override fun importedPackages(): Array<out PackageDoc> = emptyArray()
+ override fun typeParameters(): Array<out TypeVariable> = emptyArray()
+ override fun importedClasses(): Array<out ClassDoc> = emptyArray()
+ override fun isExternalizable(): Boolean = false
+ override fun definesSerializableFields(): Boolean = false
+ override fun methods(): Array<out MethodDoc> = members(DocumentationNode.Kind.Function).map { MethodAdapter(module, it) }.toTypedArray()
+ override fun fields(): Array<out FieldDoc> = members(DocumentationNode.Kind.Property).map { FieldAdapter(module, it) }.toTypedArray()
+ override fun methods(filter: Boolean): Array<out MethodDoc> = methods()
+ override fun fields(filter: Boolean): Array<out FieldDoc> = fields()
+ override fun constructors(): Array<out ConstructorDoc> = emptyArray()
+ override fun constructors(filter: Boolean): Array<out ConstructorDoc> = constructors()
+ override fun enumConstants(): Array<out FieldDoc> = emptyArray()
+ override fun isAbstract(): Boolean = false
+ override fun interfaceTypes(): Array<out Type> = emptyArray()
+ override fun interfaces(): Array<out ClassDoc> = emptyArray()
+ override fun typeParamTags(): Array<out ParamTag> = emptyArray()
+ override fun findClass(className: String?): ClassDoc? = null // TODO ???
+ override fun serializableFields(): Array<out FieldDoc> = emptyArray()
+ override fun superclassType(): Type? = null
+ override fun serializationMethods(): Array<out MethodDoc> = emptyArray()
+ override fun superclass(): ClassDoc? = null
+ override fun isSerializable(): Boolean = false
+ override fun subclassOf(cd: ClassDoc?): Boolean = false
+ override fun innerClasses(): Array<out ClassDoc> = emptyArray()
+ override fun innerClasses(filter: Boolean): Array<out ClassDoc> = innerClasses()
+ override fun isOrdinaryClass(): Boolean = true
+ override fun isClass(): Boolean = true
+
+ private fun members(kind: DocumentationNode.Kind) = packageNode.members(kind) + packageNode.members(DocumentationNode.Kind.ExternalClass).flatMap { it.members(kind) }
+}
+
+fun DocumentationNode.lookupSuperClasses(module: ModuleNodeAdapter) =
+ details(DocumentationNode.Kind.Supertype)
+ .map { it.links.firstOrNull() }
+ .map { module.allTypes[it?.qualifiedName] }
+ .filterNotNull()
+
+class ModuleNodeAdapter(val module: DocumentationModule, val reporter: DocErrorReporter) : DocumentationNodeBareAdapter(module), DocErrorReporter by reporter, RootDoc {
+ val allPackages = module.members(DocumentationNode.Kind.Package).toMap { it.name }
+ val allTypes = module.members(DocumentationNode.Kind.Package)
+ .flatMap { it.members(DocumentationNode.Kind.Class) + it.members(DocumentationNode.Kind.Interface) + it.members(DocumentationNode.Kind.Enum) }
+ .toMap { it.qualifiedName }
+ val packageFacades = module.members(DocumentationNode.Kind.Package).map { PackageFacadeAdapter(this, it) }.toMap { it.qualifiedName() }
+
+ override fun packageNamed(name: String?): PackageDoc? = allPackages[name]?.let { PackageAdapter(this, it) }
+
+ override fun classes(): Array<out ClassDoc> =
+ (allTypes.values().map { ClassDocumentationNodeAdapter(this, it) } + packageFacades.values())
+ .toTypedArray()
+
+ override fun options(): Array<out Array<String>> = arrayOf(
+ arrayOf("-d", "out/javadoc"),
+ arrayOf("-docencoding", "UTF-8")
+ )
+
+ override fun specifiedPackages(): Array<out PackageDoc>? = module.members(DocumentationNode.Kind.Package).map { PackageAdapter(this, it) }.toTypedArray()
+
+ override fun classNamed(qualifiedName: String?): ClassDoc? =
+ allTypes[qualifiedName]?.let { ClassDocumentationNodeAdapter(this, it) }
+ ?: packageFacades[qualifiedName]
+
+ override fun specifiedClasses(): Array<out ClassDoc> = classes()
+}
diff --git a/javadoc/src/main/kotlin/main.kt b/javadoc/src/main/kotlin/main.kt
new file mode 100644
index 00000000..0c3821c3
--- /dev/null
+++ b/javadoc/src/main/kotlin/main.kt
@@ -0,0 +1,24 @@
+package org.jetbrains.dokka.javadoc
+
+import com.sun.tools.doclets.formats.html.HtmlDoclet
+import org.jetbrains.dokka.DocumentationOptions
+import org.jetbrains.dokka.DokkaConsoleLogger
+import org.jetbrains.dokka.DokkaGenerator
+import org.jetbrains.dokka.buildDocumentationModule
+import java.io.File
+
+/**
+ * Test me, my friend
+ */
+public fun main(args: Array<String>) {
+ val generator = DokkaGenerator(DokkaConsoleLogger, System.getProperty("java.class.path").split(File.pathSeparator), listOf(File("test").absolutePath), emptyList(), emptyList(), "me", "out/dokka", "html", emptyList(), false)
+ val env = generator.createAnalysisEnvironment()
+ val module = buildDocumentationModule(env, generator.moduleName, DocumentationOptions(includeNonPublic = true, sourceLinks = emptyList()), emptyList(), {
+ generator.isSample(it)
+ }, generator.logger)
+
+ DokkaConsoleLogger.report()
+ HtmlDoclet.start(ModuleNodeAdapter(module, StandardReporter))
+}
+
+public fun String.a(): Int = 1 \ No newline at end of file
diff --git a/javadoc/src/main/kotlin/reporter.kt b/javadoc/src/main/kotlin/reporter.kt
new file mode 100644
index 00000000..ce80ec7b
--- /dev/null
+++ b/javadoc/src/main/kotlin/reporter.kt
@@ -0,0 +1,30 @@
+package org.jetbrains.dokka.javadoc
+
+import com.sun.javadoc.DocErrorReporter
+import com.sun.javadoc.SourcePosition
+
+object StandardReporter : DocErrorReporter {
+ override fun printWarning(msg: String?) {
+ System.err?.println("[WARN] $msg")
+ }
+
+ override fun printWarning(pos: SourcePosition?, msg: String?) {
+ System.err?.println("[WARN] ${pos?.file()}:${pos?.line()}:${pos?.column()}: $msg")
+ }
+
+ override fun printError(msg: String?) {
+ System.err?.println("[ERROR] $msg")
+ }
+
+ override fun printError(pos: SourcePosition?, msg: String?) {
+ System.err?.println("[ERROR] ${pos?.file()}:${pos?.line()}:${pos?.column()}: $msg")
+ }
+
+ override fun printNotice(msg: String?) {
+ System.err?.println("[NOTICE] $msg")
+ }
+
+ override fun printNotice(pos: SourcePosition?, msg: String?) {
+ System.err?.println("[NOTICE] ${pos?.file()}:${pos?.line()}:${pos?.column()}: $msg")
+ }
+} \ No newline at end of file
diff --git a/javadoc/src/main/kotlin/source-position.kt b/javadoc/src/main/kotlin/source-position.kt
new file mode 100644
index 00000000..0e4c6e3c
--- /dev/null
+++ b/javadoc/src/main/kotlin/source-position.kt
@@ -0,0 +1,18 @@
+package org.jetbrains.dokka.javadoc
+
+import com.sun.javadoc.SourcePosition
+import org.jetbrains.dokka.DocumentationNode
+import java.io.File
+
+class SourcePositionAdapter(val docNode: DocumentationNode) : SourcePosition {
+
+ private val sourcePositionParts: List<String> by lazy {
+ docNode.details(DocumentationNode.Kind.SourcePosition).firstOrNull()?.name?.split(":") ?: emptyList()
+ }
+
+ override fun file(): File? = if (sourcePositionParts.isEmpty()) null else File(sourcePositionParts[0])
+
+ override fun line(): Int = sourcePositionParts.getOrNull(1)?.toInt() ?: -1
+
+ override fun column(): Int = sourcePositionParts.getOrNull(2)?.toInt() ?: -1
+}
diff --git a/javadoc/src/main/kotlin/tags.kt b/javadoc/src/main/kotlin/tags.kt
new file mode 100644
index 00000000..120154f9
--- /dev/null
+++ b/javadoc/src/main/kotlin/tags.kt
@@ -0,0 +1,180 @@
+package org.jetbrains.dokka.javadoc
+
+import com.sun.javadoc.*
+import org.jetbrains.dokka.*
+import java.util.ArrayList
+
+class TextTag(val holder: Doc, val content: ContentText) : Tag {
+ val plainText: String
+ get() = content.text
+
+ override fun name(): String = "Text"
+ override fun kind(): String = name()
+ override fun text(): String? = plainText
+ override fun inlineTags(): Array<out Tag> = arrayOf(this)
+ override fun holder(): Doc = holder
+ override fun firstSentenceTags(): Array<out Tag> = arrayOf(this)
+ override fun position(): SourcePosition = holder.position()
+}
+
+abstract class SeeTagAdapter(val holder: Doc, val content: ContentNodeLink) : SeeTag {
+ override fun position(): SourcePosition? = holder.position()
+ override fun name(): String = "@see"
+ override fun kind(): String = "@see"
+ override fun holder(): Doc = holder
+
+ override fun text(): String? = content.node?.name ?: "(?)"
+}
+
+class SeeExternalLinkTagAdapter(val holder: Doc, val link: ContentExternalLink) : SeeTag {
+ override fun position(): SourcePosition = holder.position()
+ override fun text(): String = label()
+ override fun inlineTags(): Array<out Tag> = emptyArray() // TODO
+ override fun label(): String = "<a href=\"${link.href}\">${link.href}</a>"
+ override fun referencedPackage(): PackageDoc? = null
+ override fun referencedClass(): ClassDoc? = null
+ override fun referencedMemberName(): String? = null
+ override fun referencedClassName(): String? = null
+ override fun referencedMember(): MemberDoc? = null
+ override fun holder(): Doc = holder
+ override fun firstSentenceTags(): Array<out Tag> = inlineTags()
+ override fun name(): String = "@link"
+ override fun kind(): String = "@see"
+}
+
+class SeeMethodTagAdapter(holder: Doc, val method: MethodAdapter, content: ContentNodeLink) : SeeTagAdapter(holder, content) {
+ override fun referencedMember(): MemberDoc = method
+ override fun referencedMemberName(): String = method.name()
+ override fun referencedPackage(): PackageDoc? = null
+ override fun referencedClass(): ClassDoc = method.containingClass()
+ override fun referencedClassName(): String = method.containingClass().name()
+ override fun label(): String = "fun ${method.containingClass().name()}.${method.name()}"
+
+ override fun inlineTags(): Array<out Tag> = emptyArray() // TODO
+ override fun firstSentenceTags(): Array<out Tag> = inlineTags() // TODO
+}
+
+class SeeClassTagAdapter(holder: Doc, val clazz: ClassDocumentationNodeAdapter, content: ContentNodeLink) : SeeTagAdapter(holder, content) {
+ override fun referencedMember(): MemberDoc? = null
+ override fun referencedMemberName(): String? = null
+ override fun referencedPackage(): PackageDoc? = null
+ override fun referencedClass(): ClassDoc = clazz
+ override fun referencedClassName(): String = clazz.name()
+ override fun label(): String = "${clazz.classNode.kind.name().toLowerCase()} ${clazz.name()}" // TODO
+
+ override fun inlineTags(): Array<out Tag> = emptyArray() // TODO
+ override fun firstSentenceTags(): Array<out Tag> = inlineTags() // TODO
+}
+
+class ParamTagAdapter(val module: ModuleNodeAdapter, val holder: Doc, val parameterName: String, val isTypeParameter: Boolean, val content: List<ContentNode>) : ParamTag {
+ constructor(module: ModuleNodeAdapter, holder: Doc, parameterName: String, isTypeParameter: Boolean, content: ContentNode) : this(module, holder, parameterName, isTypeParameter, listOf(content))
+
+ override fun name(): String = "@param"
+ override fun kind(): String = name()
+ override fun holder(): Doc = holder
+ override fun position(): SourcePosition? = holder.position()
+
+ override fun text(): String = "@param $parameterName ..."
+ override fun inlineTags(): Array<out Tag> = content.flatMap { buildInlineTags(module, holder, it) }.toTypedArray()
+ override fun firstSentenceTags(): Array<out Tag> = arrayOf(TextTag(holder, ContentText(text())))
+
+ override fun isTypeParameter(): Boolean = isTypeParameter
+ override fun parameterComment(): String = content.toString() // TODO
+ override fun parameterName(): String = parameterName
+}
+
+
+class ThrowsTagAdapter(val holder: Doc, val type: ClassDocumentationNodeAdapter) : ThrowsTag {
+ override fun name(): String = "@throws"
+ override fun kind(): String = name()
+ override fun holder(): Doc = holder
+ override fun position(): SourcePosition? = holder.position()
+
+ override fun text(): String = "@throws ${type.qualifiedTypeName()}"
+ override fun inlineTags(): Array<out Tag> = emptyArray()
+ override fun firstSentenceTags(): Array<out Tag> = emptyArray()
+
+ override fun exceptionComment(): String = ""
+ override fun exceptionType(): Type = type
+ override fun exception(): ClassDoc = type
+ override fun exceptionName(): String = type.qualifiedName()
+}
+
+fun buildInlineTags(module: ModuleNodeAdapter, holder: Doc, root: ContentNode): List<Tag> = ArrayList<Tag>().let { buildInlineTags(module, holder, root, it); it }
+
+private fun buildInlineTags(module: ModuleNodeAdapter, holder: Doc, node: ContentNode, result: MutableList<Tag>) {
+ when (node) {
+ is ContentText -> result.add(TextTag(holder, node))
+ is ContentNodeLink -> {
+ when (node.node?.kind) {
+ DocumentationNode.Kind.Function -> result.add(SeeMethodTagAdapter(holder, MethodAdapter(module, node.node!!), node))
+
+ DocumentationNode.Kind.Class,
+ DocumentationNode.Kind.ExternalClass,
+ DocumentationNode.Kind.Enum -> result.add(SeeClassTagAdapter(holder, ClassDocumentationNodeAdapter(module, node.node!!), node))
+
+ else -> result.add(TextTag(holder, ContentText("other link: ${node.node}"))) // TODO
+ }
+ }
+ is ContentExternalLink -> result.add(SeeExternalLinkTagAdapter(holder, node))
+ is ContentCode -> surroundWith(module, holder, "<code>", "</code>", node, result)
+ is ContentBlockCode -> surroundWith(module, holder, "<code><pre>", "</pre></code>", node, result)
+ is ContentEmpty -> {}
+ is ContentEmphasis -> surroundWith(module, holder, "<em>", "</em>", node, result)
+ is ContentHeading -> surroundWith(module, holder, "<h${node.level}>", "</h${node.level}>", node, result)
+ is ContentEntity -> result.add(TextTag(holder, ContentText(node.text))) // TODO ??
+ is ContentIdentifier -> result.add(TextTag(holder, ContentText(node.text))) // TODO
+ is ContentKeyword -> result.add(TextTag(holder, ContentText(node.text))) // TODO
+ is ContentListItem -> surroundWith(module, holder, "<li>", "</li>", node, result)
+ is ContentOrderedList -> surroundWith(module, holder, "<ol>", "</ol>", node, result)
+ is ContentUnorderedList -> surroundWith(module, holder, "<ul>", "</ul>", node, result)
+ is ContentParagraph -> surroundWith(module, holder, "<p>", "</p>", node, result)
+ is ContentSection -> surroundWith(module, holder, "<p>", "</p>", node, result) // TODO how section should be represented?
+ is ContentNonBreakingSpace -> result.add(TextTag(holder, ContentText("&nbsp;")))
+ is ContentStrikethrough -> surroundWith(module, holder, "<strike>", "</strike>", node, result)
+ is ContentStrong -> surroundWith(module, holder, "<strong>", "</strong>", node, result)
+ is ContentSymbol -> result.add(TextTag(holder, ContentText(node.text))) // TODO?
+ is Content -> {
+ surroundWith(module, holder, "<p>", "</p>", node.summary, result)
+ surroundWith(module, holder, "<p>", "</p>", node.description, result)
+// node.sections.forEach {
+// buildInlineTags(module, holder, it, result)
+// }
+ }
+
+ else -> result.add(TextTag(holder, ContentText("$node")))
+ }
+}
+
+fun surroundWith(module: ModuleNodeAdapter, holder: Doc, prefix: String, postfix: String, node: ContentBlock, result: MutableList<Tag>) {
+ if (node.children.isNotEmpty()) {
+ val open = TextTag(holder, ContentText(prefix))
+ val close = TextTag(holder, ContentText(postfix))
+
+ result.add(open)
+ node.children.forEach {
+ buildInlineTags(module, holder, it, result)
+ }
+
+ if (result.last() === open) {
+ result.remove(result.lastIndex)
+ } else {
+ result.add(close)
+ }
+ }
+}
+
+fun surroundWith(module: ModuleNodeAdapter, holder: Doc, prefix: String, postfix: String, node: ContentNode, result: MutableList<Tag>) {
+ if (node !is ContentEmpty) {
+ val open = TextTag(holder, ContentText(prefix))
+ val close = TextTag(holder, ContentText(postfix))
+
+ result.add(open)
+ buildInlineTags(module, holder, node, result)
+ if (result.last() === open) {
+ result.remove(result.lastIndex)
+ } else {
+ result.add(close)
+ }
+ }
+} \ No newline at end of file
diff --git a/javadoc/src/main/kotlin/utils.kt b/javadoc/src/main/kotlin/utils.kt
new file mode 100644
index 00000000..661de0c8
--- /dev/null
+++ b/javadoc/src/main/kotlin/utils.kt
@@ -0,0 +1,10 @@
+package org.jetbrains.dokka.javadoc
+
+import org.jetbrains.dokka.DocumentationNode
+import org.jetbrains.dokka.path
+import java.util.*
+
+val DocumentationNode.qualifiedName: String
+ get() = this.path.filter { it.kind == DocumentationNode.Kind.Package || it.kind in allClassKinds }
+ .map { it.name }
+ .joinToString(".")