Skip to content

Commit be16cc0

Browse files
authored
Merge pull request scala#6 from romanowski/basic-methods
Create Scala signature provider that renders methods and classes
2 parents 3215fd8 + 31956e2 commit be16cc0

18 files changed

+666
-115
lines changed

dokkaJavaApi/src/main/kotlin/dokka.java.api.JavaPlugin.kt

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,21 @@ package dokka.java.api
33
import org.jetbrains.dokka.CoreExtensions
44
import org.jetbrains.dokka.DokkaConfiguration
55
import org.jetbrains.dokka.base.DokkaBase
6+
import org.jetbrains.dokka.base.signatures.KotlinSignatureProvider
7+
import org.jetbrains.dokka.base.signatures.SignatureProvider
8+
import org.jetbrains.dokka.base.transformers.pages.comments.CommentsToContentConverter
9+
import org.jetbrains.dokka.base.translators.documentables.PageContentBuilder
610
import org.jetbrains.dokka.model.DModule
11+
import org.jetbrains.dokka.model.Documentable
12+
import org.jetbrains.dokka.pages.ContentGroup
13+
import org.jetbrains.dokka.pages.ContentKind
14+
import org.jetbrains.dokka.pages.Kind
15+
import org.jetbrains.dokka.pages.Style
716
import org.jetbrains.dokka.plugability.DokkaContext
817
import org.jetbrains.dokka.plugability.DokkaPlugin
9-
import org.jetbrains.dokka.transformers.documentation.PreMergeDocumentableTransformer
1018
import org.jetbrains.dokka.transformers.sources.SourceToDocumentableTranslator
19+
import org.jetbrains.dokka.utilities.DokkaLogger
20+
import java.util.function.Consumer
1121

1222
data class SourceSetWrapper(val sourceSet: DokkaConfiguration.DokkaSourceSet) {
1323
fun toSet(): Set<DokkaConfiguration.DokkaSourceSet> = setOf(sourceSet)
@@ -26,5 +36,26 @@ abstract class JavaDokkaPlugin : DokkaPlugin() {
2636
} override dokkaBase.descriptorToDocumentableTranslator
2737
}
2838

39+
val scalaSignatureProvider by extending {
40+
dokkaBase.signatureProvider providing { ctx ->
41+
createSignatureProvider(ctx.single(dokkaBase.commentsToContentConverter), ctx.logger)
42+
} override dokkaBase.kotlinSignatureProvider
43+
}
44+
2945
abstract fun createSourceToDocumentableTranslator(cxt: DokkaContext, sourceSet: SourceSetWrapper): DModule
46+
abstract fun createSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLogger): SignatureProvider
3047
}
48+
49+
// TODO we probably does not need that
50+
class JPageContentBuilder(cc: CommentsToContentConverter, sp: SignatureProvider, l: DokkaLogger) :
51+
PageContentBuilder(cc, sp, l) {
52+
fun mkContent(
53+
d: Documentable,
54+
kind: Kind = ContentKind.Main,
55+
styles: Set<Style>,
56+
op: Consumer<DocumentableContentBuilder>
57+
): ContentGroup =
58+
contentFor(d.dri, d.sourceSets, kind, styles) {
59+
op.accept(this)
60+
}
61+
}

libs/dokkaJavaApi-0.1.0.jar

5.38 KB
Binary file not shown.

src/main/scala/dotty/dokka/DottyDokkaPlugin.scala

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import dokka.java.api._
1313
import collection.JavaConverters._
1414
import org.jetbrains.dokka.model.properties.PropertyContainer
1515
import dotty.dokka.tasty.DokkaTastyInspector
16+
import org.jetbrains.dokka.base.transformers.pages.comments.CommentsToContentConverter
17+
import org.jetbrains.dokka.utilities.DokkaLogger
1618

1719
class DottyDokkaPlugin extends JavaDokkaPlugin:
1820
override def createSourceToDocumentableTranslator(cxt: DokkaContext, sourceSet: SourceSetWrapper): DModule = cxt.getConfiguration match {
@@ -30,4 +32,6 @@ class DottyDokkaPlugin extends JavaDokkaPlugin:
3032
)
3133
case _ =>
3234
???
33-
}
35+
}
36+
37+
override def createSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLogger) = new ScalaSignatureProvider(ctcc, logger)

src/main/scala/dotty/dokka/Main.scala

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,16 @@ object Main:
1919
def main(args: Array[String]): Unit =
2020
// TODO change the default to something more reasonable...
2121
val cp = args.headOption.getOrElse("target/scala-0.25/classes")
22-
def listTastyFiles(f: File): Seq[File] =
22+
def listTastyFiles(f: File): Seq[String] =
2323
val (files, dirs) = f.listFiles().partition(_.isFile)
24-
files.filter(_.getName.endsWith(".tasty")) ++ dirs.flatMap(listTastyFiles)
24+
files.filter(_.getName.endsWith(".tasty")).map(_.toString) ++ dirs.flatMap(listTastyFiles)
2525

2626
val config = DocConfiguration(
27-
tastyFiles = cp.split(File.pathSeparatorChar).toList.flatMap(p => listTastyFiles(new File(p))).map(_.toString),
27+
tastyFiles =
28+
for
29+
root <- cp.split(File.pathSeparatorChar).toList
30+
tastyFile <- listTastyFiles(new File(root)) if tastyFile.contains("tests") || tastyFile.contains("example")
31+
yield tastyFile,
2832
classpath = System.getProperty("java.class.path")
2933
)
3034

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
package dotty.dokka
2+
3+
import org.jetbrains.dokka.base.signatures._
4+
import org.jetbrains.dokka.model._
5+
import org.jetbrains.dokka.pages._
6+
import org.jetbrains.dokka.base.signatures.KotlinSignatureProvider
7+
import org.jetbrains.dokka.base.transformers.pages.comments.CommentsToContentConverter
8+
import org.jetbrains.dokka.utilities.DokkaLogger
9+
import collection.JavaConverters._
10+
import org.jetbrains.dokka.base.translators.documentables._
11+
import org.jetbrains.dokka.model.properties.PropertyContainer
12+
import dokka.java.api._
13+
import java.util.function.Consumer
14+
import kotlin.jvm.functions.Function2
15+
import java.util.{List => JList}
16+
17+
class ScalaSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLogger) extends SignatureProvider:
18+
private val default = new KotlinSignatureProvider(ctcc, logger)
19+
private val contentBuilder = new JPageContentBuilder(ctcc, this, logger)
20+
21+
override def signature(documentable: Documentable) = documentable match {
22+
case method: DFunction =>
23+
List(methodSignature(method)).asJava
24+
case clazz: DClass =>
25+
List(classSignature(clazz)).asJava
26+
case _ => default.signature(documentable)
27+
}
28+
29+
val styles = Set(TextStyle.Monospace).asJava
30+
31+
val utils: JvmSignatureUtils = KotlinSignatureUtils.INSTANCE
32+
33+
private def classSignature(clazz: DClass): ContentNode =
34+
content(clazz){ builder =>
35+
val ext = clazz.get(ClasslikeExtension)
36+
utils.annotationsBlock(builder, clazz)
37+
// builder.addText("TODO modifiers")
38+
builder.addText("class ")
39+
builder.addLink(clazz.getName, clazz.getDri)
40+
builder.generics(clazz)
41+
ext.constructor.foreach(c => builder.functionParameters(c))
42+
ext.parentTypes match
43+
case Nil =>
44+
case extendType :: withTypes =>
45+
builder.addText(" extends ")
46+
builder.typeSignature(extendType)
47+
withTypes.foreach { t =>
48+
builder.addText(" with ")
49+
builder.typeSignature(extendType)
50+
}
51+
}
52+
53+
private def methodSignature(method: DFunction): ContentNode =
54+
content(method){ builder =>
55+
utils.annotationsBlock(builder, method)
56+
// builder.addText("TODO modifiers")
57+
builder.addText("def")
58+
builder.addText(" ")
59+
builder.addLink(method.getName, method.getDri)
60+
builder.generics(method)
61+
builder.functionParameters(method)
62+
builder.addText(":")
63+
builder.addText(" ")
64+
builder.typeSignature(method.getType)
65+
}
66+
67+
68+
extension on (builder: PageContentBuilder$DocumentableContentBuilder):
69+
def typeSignature(b: Projection): Unit = b match {
70+
case tc: TypeConstructor =>
71+
tc.getProjections.asScala.foreach {
72+
case text: UnresolvedBound => builder.addText(text.getName)
73+
case link: OtherParameter =>
74+
builder.addLink(link.getName, link.getDeclarationDRI)
75+
case other =>
76+
builder.addText(s"TODO($other)")
77+
}
78+
case other =>
79+
builder.addText(s"TODO: $other")
80+
}
81+
82+
def generics(on: WithGenerics) = builder.addList(on.getGenerics, "[", "]"){ e =>
83+
builder.addText(e.getName)
84+
e.getBounds.forEach(b => builder.typeSignature(b))
85+
}
86+
87+
def functionParameters(method: DFunction) =
88+
val methodExtension = method.get(MethodExtension)
89+
methodExtension.parametersListSizes.foldLeft(0){ (from, size) =>
90+
val toIndex = from + size
91+
if from == toIndex then builder.addText("()")
92+
else builder.addList(method.getParameters.subList(from, toIndex), "(", ")"){ param =>
93+
utils.annotationsInline(builder, param)
94+
// builder.addText("TODO modifiers")
95+
builder.addText(param.getName)
96+
builder.addText(": ")
97+
builder.typeSignature(param.getType)
98+
}
99+
toIndex
100+
}
101+
102+
private def content(d: Documentable)(render: PageContentBuilder$DocumentableContentBuilder => Unit): ContentGroup =
103+
val lambda: Consumer[PageContentBuilder$DocumentableContentBuilder] = new Consumer:
104+
override def accept(v: PageContentBuilder$DocumentableContentBuilder) = render(v)
105+
106+
contentBuilder.mkContent(d, ContentKind.Symbol, styles, lambda)
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package dotty.dokka
2+
3+
import org.jetbrains.dokka.links._
4+
import org.jetbrains.dokka.model._
5+
import collection.JavaConverters._
6+
import org.jetbrains.dokka.links._
7+
import org.jetbrains.dokka.model.doc._
8+
import org.jetbrains.dokka.model.properties._
9+
10+
case class MethodExtension(parametersListSizes: Seq[Int]) extends ExtraProperty[DFunction]:
11+
override def getKey = MethodExtension
12+
13+
object MethodExtension extends BaseKey[DFunction, MethodExtension]
14+
15+
case class ClasslikeExtension(parentTypes: List[Bound], constructor: Option[DFunction]) extends ExtraProperty[DClasslike]:
16+
override def getKey = ClasslikeExtension
17+
18+
object ClasslikeExtension extends BaseKey[DClasslike, ClasslikeExtension]
19+
20+
21+
class BaseKey[T, V] extends ExtraProperty.Key[T, V]:
22+
override def mergeStrategyFor(left: V, right: V): MergeStrategy[T] =
23+
MergeStrategy.Remove.INSTANCE.asInstanceOf[MergeStrategy[T]]

src/main/scala/dotty/dokka/tasty/BasicSupport.scala

Lines changed: 29 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package dotty.dokka.tasty
33
import org.jetbrains.dokka.links._
44
import org.jetbrains.dokka.model._
55
import collection.JavaConverters._
6+
import dotty.dokka._
67

78
trait BasicSupport:
89
self: TastyParser =>
@@ -11,50 +12,42 @@ trait BasicSupport:
1112
extension SymbolOps on (sym: reflect.Symbol):
1213
def packageName(using ctx: Context): String =
1314
if (sym.isPackageDef) sym.fullName
14-
else sym.owner.packageName
15+
else sym.maybeOwner.packageName
1516

1617
def topLevelEntryName(using ctx: Context): Option[String] = if (sym.isPackageDef) None else
1718
if (sym.owner.isPackageDef) Some(sym.name) else sym.owner.topLevelEntryName
1819

19-
def dri = asDRI(sym)
20-
def declarationDri = asDRI(sym, true)
20+
// TODO make sure that DRIs are unique plus probably reuse semantic db code?
21+
def dri =
22+
if sym == Symbol.noSymbol then emptyDRI else
23+
val pointsTo =
24+
if (!sym.isTypeDef) PointingToDeclaration.INSTANCE
25+
else PointingToGenericParameters(sym.owner.typeMembers.indexOf(sym))
26+
27+
val method =
28+
if (sym.isDefDef) Some(sym)
29+
else if (sym.maybeOwner.isDefDef) Some(sym.owner)
30+
else None
31+
32+
new DRI(
33+
sym.packageName,
34+
sym.topLevelEntryName.orNull, // TODO do we need any of this fields?
35+
method.map(s => new org.jetbrains.dokka.links.Callable(s.name, null, Nil.asJava)).orNull,
36+
pointsTo, // TODO different targets?
37+
s"${sym.show}/${sym.signature.resultSig}/[${sym.signature.paramSigs.mkString("/")}]"
38+
)
2139

2240
def documentation(using cxt: reflect.Context) = sym.comment match
2341
case Some(comment) =>
2442
sourceSet.asMap(parseComment(comment, sym.tree))
2543
case None =>
2644
Map.empty.asJava
2745

28-
def source(using ctx: Context) = sourceSet.asMap(getSource(sym))
29-
30-
def dokkaType(using cxt: reflect.Context): Bound = // TODO render primitives better?
31-
// TODO support varags
32-
val params = sym.typeMembers.map(_.dokkaType)
33-
println(s"${sym.show} -> ${sym.dri}")
34-
new org.jetbrains.dokka.model.TypeConstructor(sym.dri, params.asJava, FunctionModifiers.NONE)
35-
36-
37-
38-
// TODO add support for type aliases!
39-
def asDRI(symbol: reflect.Symbol, declaration: Boolean = false): DRI =
40-
val pointsTo =
41-
if (!symbol.isTypeDef || declaration) PointingToDeclaration.INSTANCE
42-
else PointingToGenericParameters(symbol.owner.typeMembers.indexOf(symbol))
43-
44-
val method =
45-
if (symbol.isDefDef) Some(symbol)
46-
else if (symbol.owner.isDefDef) Some(symbol.owner)
47-
else None
48-
49-
new DRI(
50-
symbol.packageName,
51-
symbol.topLevelEntryName.orNull, // TODO do we need any of this fields?
52-
method.map(s => new org.jetbrains.dokka.links.Callable(s.name, null, Nil.asJava)).orNull,
53-
pointsTo, // TODO different targets?
54-
symbol.show
55-
)
56-
57-
def getSource(symbol: reflect.Symbol)(using ctx: Context): DocumentableSource =
58-
val path = symbol.pos.sourceFile.jpath.toString
59-
new DocumentableSource:
60-
override def getPath = path
46+
def source(using ctx: Context) =
47+
val path = sym.pos.sourceFile.jpath.toString
48+
sourceSet.asMap(
49+
new DocumentableSource:
50+
override def getPath = path
51+
)
52+
53+
private val emptyDRI = DRI.Companion.getTopLevel

0 commit comments

Comments
 (0)