1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
|
package org.jetbrains.dokka.javadoc
import com.sun.javadoc.*
import org.jetbrains.dokka.*
import java.lang.reflect.Modifier
import java.util.*
import kotlin.reflect.KClass
private interface HasModule {
val module: ModuleNodeAdapter
}
private interface HasDocumentationNode {
val node: DocumentationNode
}
open class DocumentationNodeBareAdapter(override val node: DocumentationNode) : Doc, HasDocumentationNode {
private var rawCommentText_: String? = null
override fun name(): String = node.name
override fun position(): SourcePosition? = SourcePositionAdapter(node)
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 = node.kind == NodeKind.Exception
override fun isEnumConstant(): Boolean = node.kind == NodeKind.EnumItem
override fun isEnum(): Boolean = node.kind == NodeKind.Enum
override fun isMethod(): Boolean = node.kind == NodeKind.Function
override fun isInterface(): Boolean = node.kind == NodeKind.Interface
override fun isField(): Boolean = node.kind == NodeKind.Field
override fun isClass(): Boolean = node.kind == NodeKind.Class
override fun isAnnotationType(): Boolean = node.kind == NodeKind.AnnotationClass
override fun isConstructor(): Boolean = node.kind == NodeKind.Constructor
override fun isOrdinaryClass(): Boolean = node.kind == NodeKind.Class
override fun isAnnotationTypeElement(): Boolean = node.kind == NodeKind.Annotation
override fun compareTo(other: Any?): Int = when (other) {
!is DocumentationNodeAdapter -> 1
else -> node.name.compareTo(other.node.name)
}
override fun equals(other: Any?): Boolean = node.qualifiedName() == (other as? DocumentationNodeAdapter)?.node?.qualifiedName()
override fun hashCode(): Int = node.name.hashCode()
override fun isIncluded(): Boolean = node.kind != NodeKind.ExternalClass
}
// TODO think of source position instead of null
// TODO tags
open class DocumentationNodeAdapter(override val module: ModuleNodeAdapter, node: DocumentationNode) : DocumentationNodeBareAdapter(node), HasModule {
override fun inlineTags(): Array<out Tag> = buildInlineTags(module, this, node.content).toTypedArray()
override fun firstSentenceTags(): Array<out Tag> = buildInlineTags(module, this, node.summary).toTypedArray()
override fun tags(): Array<out Tag> {
val result = ArrayList<Tag>(buildInlineTags(module, this, node.content))
node.content.sections.flatMapTo(result) {
when (it.tag) {
ContentTags.SeeAlso -> buildInlineTags(module, this, it)
else -> emptyList<Tag>()
}
}
node.deprecation?.let {
val content = it.content.asText()
if (content != null) {
result.add(TagImpl(this, "deprecated", content))
}
}
return result.toTypedArray()
}
}
// should be extension property but can't because of KT-8745
private fun <T> nodeAnnotations(self: T): List<AnnotationDescAdapter> where T : HasModule, T : HasDocumentationNode
= self.node.annotations.map { AnnotationDescAdapter(self.module, it) }
private fun DocumentationNode.hasAnnotation(klass: KClass<*>) = klass.qualifiedName in annotations.map { it.qualifiedName() }
private fun DocumentationNode.hasModifier(name: String) = details(NodeKind.Modifier).any { it.name == name }
class PackageAdapter(module: ModuleNodeAdapter, node: DocumentationNode) : DocumentationNodeAdapter(module, node), PackageDoc {
private val allClasses = listOf(node).collectAllTypesRecursively()
override fun findClass(className: String?): ClassDoc? =
allClasses.get(className)?.let { ClassDocumentationNodeAdapter(module, it) }
override fun annotationTypes(): Array<out AnnotationTypeDoc> = emptyArray()
override fun annotations(): Array<out AnnotationDesc> = node.members(NodeKind.AnnotationClass).map { AnnotationDescAdapter(module, it) }.toTypedArray()
override fun exceptions(): Array<out ClassDoc> = node.members(NodeKind.Exception).map { ClassDocumentationNodeAdapter(module, it) }.toTypedArray()
override fun ordinaryClasses(): Array<out ClassDoc> = node.members(NodeKind.Class).map { ClassDocumentationNodeAdapter(module, it) }.toTypedArray()
override fun interfaces(): Array<out ClassDoc> = node.members(NodeKind.Interface).map { ClassDocumentationNodeAdapter(module, it) }.toTypedArray()
override fun errors(): Array<out ClassDoc> = emptyArray()
override fun enums(): Array<out ClassDoc> = node.members(NodeKind.Enum).map { ClassDocumentationNodeAdapter(module, it) }.toTypedArray()
override fun allClasses(filter: Boolean): Array<out ClassDoc> = allClasses.values.map { ClassDocumentationNodeAdapter(module, it) }.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
}
open class ProgramElementAdapter(module: ModuleNodeAdapter, node: DocumentationNode) : DocumentationNodeAdapter(module, node), ProgramElementDoc {
override fun isPublic(): Boolean = true
override fun isPackagePrivate(): Boolean = false
override fun isStatic(): Boolean = node.hasModifier("static")
override fun modifierSpecifier(): Int = Modifier.PUBLIC + if (isStatic) Modifier.STATIC else 0
override fun qualifiedName(): String? = node.qualifiedName()
override fun annotations(): Array<out AnnotationDesc>? = nodeAnnotations(this).toTypedArray()
override fun modifiers(): String? = "public ${if (isStatic) "static" else ""}".trim()
override fun isProtected(): Boolean = false
override fun isFinal(): Boolean = node.hasModifier("final")
override fun containingPackage(): PackageDoc? {
if (node.kind == NodeKind.Type) {
return null
}
var owner: DocumentationNode? = node
while (owner != null) {
if (owner.kind == NodeKind.Package) {
return PackageAdapter(module, owner)
}
owner = owner.owner
}
return null
}
override fun containingClass(): ClassDoc? {
if (node.kind == NodeKind.Type) {
return null
}
var owner = node.owner
while (owner != null) {
if (owner.kind in NodeKind.classLike) {
return ClassDocumentationNodeAdapter(module, owner)
}
owner = owner.owner
}
return null
}
override fun isPrivate(): Boolean = false
override fun isIncluded(): Boolean = containingPackage()?.isIncluded ?: false && containingClass()?.let { it.isIncluded } ?: true
}
open class TypeAdapter(override val module: ModuleNodeAdapter, override val node: DocumentationNode) : Type, HasDocumentationNode, HasModule {
private val javaLanguageService = JavaLanguageService()
override fun qualifiedTypeName(): String = javaLanguageService.getArrayElementType(node)?.qualifiedNameFromType() ?: node.qualifiedNameFromType()
override fun typeName(): String = javaLanguageService.getArrayElementType(node)?.simpleName() ?: node.simpleName()
override fun simpleTypeName(): String = typeName() // TODO difference typeName() vs simpleTypeName()
override fun dimension(): String = Collections.nCopies(javaLanguageService.getArrayDimension(node), "[]").joinToString("")
override fun isPrimitive(): Boolean = simpleTypeName() in setOf("int", "long", "short", "byte", "char", "double", "float", "boolean", "void")
override fun asClassDoc(): ClassDoc? = if (isPrimitive) null else
elementType?.asClassDoc() ?:
when (node.kind) {
in NodeKind.classLike,
NodeKind.ExternalClass,
NodeKind.Exception -> module.classNamed(qualifiedTypeName()) ?: 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 == NodeKind.TypeParameter) TypeVariableAdapter(module, node) else null
override fun asParameterizedType(): ParameterizedType? =
if (node.details(NodeKind.Type).isNotEmpty() && javaLanguageService.getArrayElementType(node) == null)
ParameterizedTypeAdapter(module, node)
else
null
override fun asAnnotationTypeDoc(): AnnotationTypeDoc? = if (node.kind == NodeKind.AnnotationClass) AnnotationTypeDocAdapter(module, node) else null
override fun asAnnotatedType(): AnnotatedType? = if (node.annotations.isNotEmpty()) AnnotatedTypeAdapter(module, node) else null
override fun getElementType(): Type? = javaLanguageService.getArrayElementType(node)?.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 NotAnnotatedTypeAdapter(typeAdapter: AnnotatedTypeAdapter) : Type by typeAdapter {
override fun asAnnotatedType() = null
}
class AnnotatedTypeAdapter(module: ModuleNodeAdapter, node: DocumentationNode) : TypeAdapter(module, node), AnnotatedType {
override fun underlyingType(): Type? = NotAnnotatedTypeAdapter(this)
override fun annotations(): Array<out AnnotationDesc> = nodeAnnotations(this).toTypedArray()
}
class WildcardTypeAdapter(module: ModuleNodeAdapter, node: DocumentationNode) : TypeAdapter(module, node), WildcardType {
override fun extendsBounds(): Array<out Type> = node.details(NodeKind.UpperBound).map { TypeAdapter(module, it) }.toTypedArray()
override fun superBounds(): Array<out Type> = node.details(NodeKind.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) {
NodeKind.Function,
NodeKind.Constructor -> ExecutableMemberAdapter(module, owner)
NodeKind.Class,
NodeKind.Interface,
NodeKind.Enum -> ClassDocumentationNodeAdapter(module, owner)
else -> ProgramElementAdapter(module, node.owner!!)
}
}
override fun bounds(): Array<out Type>? = node.details(NodeKind.UpperBound).map { TypeAdapter(module, it) }.toTypedArray()
override fun annotations(): Array<out AnnotationDesc>? = node.members(NodeKind.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
}
class ParameterizedTypeAdapter(module: ModuleNodeAdapter, node: DocumentationNode) : TypeAdapter(module, node), ParameterizedType {
override fun typeArguments(): Array<out Type> = node.details(NodeKind.Type).map { TypeVariableAdapter(module, it) }.toTypedArray()
override fun superclassType(): Type? =
node.lookupSuperClasses(module)
.firstOrNull { it.kind == NodeKind.Class || it.kind == NodeKind.ExternalClass }
?.let { ClassDocumentationNodeAdapter(module, it) }
override fun interfaceTypes(): Array<out Type> =
node.lookupSuperClasses(module)
.filter { it.kind == NodeKind.Interface }
.map { ClassDocumentationNodeAdapter(module, it) }
.toTypedArray()
override fun containingType(): Type? = when (node.owner?.kind) {
NodeKind.Package -> null
NodeKind.Class,
NodeKind.Interface,
NodeKind.Object,
NodeKind.Enum -> ClassDocumentationNodeAdapter(module, node.owner!!)
else -> null
}
}
class ParameterAdapter(module: ModuleNodeAdapter, node: DocumentationNode) : DocumentationNodeAdapter(module, node), Parameter {
override fun typeName(): String? = JavaLanguageService().renderType(node.detail(NodeKind.Type))
override fun type(): Type? = TypeAdapter(module, node.detail(NodeKind.Type))
override fun annotations(): Array<out AnnotationDesc> = nodeAnnotations(this).toTypedArray()
}
class ReceiverParameterAdapter(module: ModuleNodeAdapter, val receiverType: DocumentationNode, val parent: ExecutableMemberAdapter) : DocumentationNodeAdapter(module, receiverType), Parameter {
override fun typeName(): String? = receiverType.name
override fun type(): Type? = TypeAdapter(module, receiverType)
override fun annotations(): Array<out AnnotationDesc> = nodeAnnotations(this).toTypedArray()
override fun name(): String = tryName("receiver")
private tailrec fun tryName(name: String): String = when (name) {
in parent.parameters().drop(1).map { it.name() } -> tryName("$$name")
else -> name
}
}
fun classOf(fqName: String, kind: NodeKind = NodeKind.Class) = DocumentationNode(fqName.substringAfterLast(".", fqName), Content.Empty, kind).let { node ->
val pkg = fqName.substringBeforeLast(".", "")
if (pkg.isNotEmpty()) {
node.append(DocumentationNode(pkg, Content.Empty, NodeKind.Package), RefKind.Owner)
}
node
}
private fun DocumentationNode.hasNonEmptyContent() =
this.content.summary !is ContentEmpty || this.content.description !is ContentEmpty || this.content.sections.isNotEmpty()
open class ExecutableMemberAdapter(module: ModuleNodeAdapter, node: DocumentationNode) : 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 == ContentTags.Exceptions && it.subjectName != null }
.map { ThrowsTagAdapter(this, ClassDocumentationNodeAdapter(module, classOf(it.subjectName!!, NodeKind.Exception)), it.children) }
.toTypedArray()
override fun isVarArgs(): Boolean = node.details(NodeKind.Parameter).any { false } // TODO
override fun isSynchronized(): Boolean = node.annotations.any { it.name == "synchronized" }
override fun paramTags(): Array<out ParamTag> =
collectParamTags(NodeKind.Parameter, sectionFilter = { it.subjectName in parameters().map { it.name() } })
override fun thrownExceptionTypes(): Array<out Type> = emptyArray()
override fun receiverType(): Type? = receiverNode()?.let { receiver -> TypeAdapter(module, receiver) }
override fun flatSignature(): String = node.details(NodeKind.Parameter).map { JavaLanguageService().renderType(it) }.joinToString(", ", "(", ")")
override fun signature(): String = node.details(NodeKind.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, this)) } ?: emptyList())
+ node.details(NodeKind.Parameter).map { ParameterAdapter(module, it) }
).toTypedArray()
override fun typeParameters(): Array<out TypeVariable> = node.details(NodeKind.TypeParameter).map { TypeVariableAdapter(module, it) }.toTypedArray()
override fun typeParamTags(): Array<out ParamTag> =
collectParamTags(NodeKind.TypeParameter, sectionFilter = { it.subjectName in typeParameters().map { it.simpleTypeName() } })
private fun receiverNode() = node.details(NodeKind.Receiver).let { receivers ->
when {
receivers.isNotEmpty() -> receivers.single().detail(NodeKind.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")
override fun containingClass(): ClassDoc? {
return super.containingClass()
}
}
class MethodAdapter(module: ModuleNodeAdapter, node: DocumentationNode) : 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(NodeKind.Type))
override fun tags(tagname: String?) = super.tags(tagname)
override fun tags(): Array<out Tag> {
val tags = super.tags().toMutableList()
node.content.findSectionByTag(ContentTags.Return)?.let {
tags += ReturnTagAdapter(module, this, it.children)
}
return tags.toTypedArray()
}
}
class FieldAdapter(module: ModuleNodeAdapter, node: DocumentationNode) : ProgramElementAdapter(module, node), FieldDoc {
override fun isSynthetic(): Boolean = false
override fun constantValueExpression(): String? = node.detailOrNull(NodeKind.Value)?.let { it.name }
override fun constantValue(): Any? = constantValueExpression()
override fun type(): Type = TypeAdapter(module, node.detail(NodeKind.Type))
override fun isTransient(): Boolean = node.hasAnnotation(Transient::class)
override fun serialFieldTags(): Array<out SerialFieldTag> = emptyArray()
override fun isVolatile(): Boolean = node.hasAnnotation(Volatile::class)
}
open class ClassDocumentationNodeAdapter(module: ModuleNodeAdapter, val classNode: DocumentationNode)
: ProgramElementAdapter(module, classNode),
Type by TypeAdapter(module, classNode),
ClassDoc {
override fun name(): String {
val parent = classNode.owner
if (parent?.kind in NodeKind.classLike) {
return parent!!.name + "." + classNode.name
}
return classNode.simpleName()
}
override fun constructors(filter: Boolean): Array<out ConstructorDoc> = classNode.members(NodeKind.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(NodeKind.TypeParameter).map { TypeVariableAdapter(module, it) }.toTypedArray()
override fun asTypeVariable(): TypeVariable? = if (classNode.kind == NodeKind.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(NodeKind.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(NodeKind.EnumItem).map { FieldAdapter(module, it) }.toTypedArray()
override fun isAbstract(): Boolean = classNode.details(NodeKind.Modifier).any { it.name == "abstract" }
override fun interfaceTypes(): Array<out Type> = classNode.lookupSuperClasses(module)
.filter { it.kind == NodeKind.Interface }
.map { ClassDocumentationNodeAdapter(module, it) }
.toTypedArray()
override fun interfaces(): Array<out ClassDoc> = classNode.lookupSuperClasses(module)
.filter { it.kind == NodeKind.Interface }
.map { ClassDocumentationNodeAdapter(module, it) }
.toTypedArray()
override fun typeParamTags(): Array<out ParamTag> =
collectParamTags(NodeKind.TypeParameter, sectionFilter = { it.subjectName in typeParameters().map { it.simpleTypeName() } })
override fun fields(): Array<out FieldDoc> = fields(true)
override fun fields(filter: Boolean): Array<out FieldDoc> = classNode.members(NodeKind.Field).map { FieldAdapter(module, it) }.toTypedArray()
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 == NodeKind.Class }?.let { ClassDocumentationNodeAdapter(module, it) }
override fun serializationMethods(): Array<out MethodDoc> = emptyArray() // TODO
override fun superclass(): ClassDoc? = classNode.lookupSuperClasses(module).singleOrNull { it.kind == NodeKind.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.removeAt(types.lastIndex)
val fqName = type.qualifiedName()
if (expectedFQName == fqName) {
return true
}
visitedTypes.add(fqName)
types.addAll(type.details(NodeKind.Supertype).filter { it.qualifiedName() !in visitedTypes })
}
return false
}
override fun innerClasses(): Array<out ClassDoc> = classNode.members(NodeKind.Class).map { ClassDocumentationNodeAdapter(module, it) }.toTypedArray()
override fun innerClasses(filter: Boolean): Array<out ClassDoc> = innerClasses()
}
fun DocumentationNode.lookupSuperClasses(module: ModuleNodeAdapter) =
details(NodeKind.Supertype)
.map { it.links.firstOrNull() }
.map { module.allTypes[it?.qualifiedName()] }
.filterNotNull()
fun List<DocumentationNode>.collectAllTypesRecursively(): Map<String, DocumentationNode> {
val result = hashMapOf<String, DocumentationNode>()
fun DocumentationNode.collectTypesRecursively() {
val classLikeMembers = NodeKind.classLike.flatMap { members(it) }
classLikeMembers.forEach {
result.put(it.qualifiedName(), it)
it.collectTypesRecursively()
}
}
forEach { it.collectTypesRecursively() }
return result
}
class ModuleNodeAdapter(val module: DocumentationModule, val reporter: DocErrorReporter, val outputPath: String) : DocumentationNodeBareAdapter(module), DocErrorReporter by reporter, RootDoc {
val allPackages = module.members(NodeKind.Package).associateBy { it.name }
val allTypes = module.members(NodeKind.Package).collectAllTypesRecursively()
override fun packageNamed(name: String?): PackageDoc? = allPackages[name]?.let { PackageAdapter(this, it) }
override fun classes(): Array<out ClassDoc> =
allTypes.values.map { ClassDocumentationNodeAdapter(this, it) }.toTypedArray()
override fun options(): Array<out Array<String>> = arrayOf(
arrayOf("-d", outputPath),
arrayOf("-docencoding", "UTF-8"),
arrayOf("-charset", "UTF-8"),
arrayOf("-keywords")
)
override fun specifiedPackages(): Array<out PackageDoc>? = module.members(NodeKind.Package).map { PackageAdapter(this, it) }.toTypedArray()
override fun classNamed(qualifiedName: String?): ClassDoc? =
allTypes[qualifiedName]?.let { ClassDocumentationNodeAdapter(this, it) }
override fun specifiedClasses(): Array<out ClassDoc> = classes()
}
private fun DocumentationNodeAdapter.collectParamTags(kind: NodeKind, sectionFilter: (ContentSection) -> Boolean) =
(node.details(kind)
.filter(DocumentationNode::hasNonEmptyContent)
.map { ParamTagAdapter(module, this, it.name, true, it.content.children) }
+ node.content.sections
.filter(sectionFilter)
.map { ParamTagAdapter(module, this, it.subjectName ?: "?", true, it.children) })
.toTypedArray()
|