1 /*
2 * Copyright (C) 2024 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.conscrypt.doclet
18
19 import org.conscrypt.doclet.FilterDoclet.Companion.baseUrl
20 import com.sun.source.doctree.DocCommentTree
21 import com.sun.source.doctree.DocTree
22 import com.sun.source.doctree.EndElementTree
23 import com.sun.source.doctree.LinkTree
24 import com.sun.source.doctree.LiteralTree
25 import com.sun.source.doctree.ParamTree
26 import com.sun.source.doctree.ReturnTree
27 import com.sun.source.doctree.SeeTree
28 import com.sun.source.doctree.StartElementTree
29 import com.sun.source.doctree.TextTree
30 import com.sun.source.doctree.ThrowsTree
31 import org.conscrypt.doclet.FilterDoclet.Companion.classIndex
32 import org.conscrypt.doclet.FilterDoclet.Companion.docTrees
33 import javax.lang.model.element.Element
34 import javax.lang.model.type.TypeMirror
35
renderDocTreeListnull36 fun renderDocTreeList(treeList: List<DocTree>):String =
37 treeList.joinToString("\n", transform = ::renderDocTree)
38
39 fun renderDocTree(docTree: DocTree): String = when (docTree) {
40 is TextTree -> docTree.body
41 is LinkTree -> {
42 val reference = docTree.reference.toString()
43 val label = if (docTree.label.isEmpty()) {
44 reference
45 } else {
46 renderDocTreeList(docTree.label)
47 }
48 createLink(reference, label)
49 }
50 is StartElementTree, is EndElementTree -> docTree.toString()
51 is LiteralTree -> "<code>${docTree.body}</code>"
52 else -> error("[${docTree.javaClass} / ${docTree.kind} --- ${docTree}]")
53 }
54
<lambda>null55 fun createLink(reference: String, label: String) = html {
56 val parts = reference.split('#')
57 val className = parts[0]
58 val anchor = if (parts.size > 1) "#${parts[1]}" else ""
59 val classInfo = classIndex.find(className)
60 val href = if (classInfo != null)
61 "${classInfo.simpleName}.html$anchor"
62 else
63 "$baseUrl${className.replace('.', '/')}.html$anchor"
64
65 a(href, label)
66 }
67
renderBlockTagListnull68 fun renderBlockTagList(tagList: List<DocTree>): String =
69 tagList.joinToString("\n", transform = ::renderBlockTag)
70
71 fun renderBlockTag(tag: DocTree) = when (tag) {
72 is ParamTree, is ReturnTree, is ThrowsTree -> error("Unexpected block tag: $tag")
73 is SeeTree -> html {
74 br()
75 p {
76 strong("See: ")
77 text(renderDocTreeList(tag.reference))
78 }
79 }
80 else -> tag.toString()
81 }
82
filterTagsnull83 inline fun <reified T> Element.filterTags() =
84 docTree()?.blockTags?.filterIsInstance<T>() ?: emptyList()
85
86 fun Element.paramTags() = filterTags<ParamTree>()
87 .map { it.name.toString() to renderDocTreeList(it.description) }
88 .toList()
89
90
Elementnull91 fun Element.returnTag(returnType: TypeMirror): List<Pair<String, String>> {
92 val list = mutableListOf<Pair<String, String>>()
93 val descriptions = filterTags<ReturnTree>()
94 .map { renderDocTreeList(it.description) }
95 .singleOrNull()
96
97 if (descriptions != null) {
98 list.add(returnType.toString() to descriptions)
99 }
100 return list
101 }
102
Elementnull103 fun Element.throwTags() = filterTags<ThrowsTree>()
104 .map { it.exceptionName.toString() to renderDocTreeList(it.description) }
105 .toList()
106
docTreenull107 fun Element.docTree(): DocCommentTree? = docTrees.getDocCommentTree(this)
108 fun Element.commentTree() = docTree()?.let { renderDocTreeList(it.fullBody) } ?: ""
<lambda>null109 fun Element.tagTree() = docTree()?.let { renderBlockTagList(it.blockTags) } ?: ""
Elementnull110 fun Element.commentsAndTagTrees() = commentTree() + tagTree()
111