Skip to content

Commit aa58974

Browse files
committed
Add sealed keyword to graphs to put emphasis on sealed relation
1 parent 49c59f5 commit aa58974

File tree

9 files changed

+186
-21
lines changed

9 files changed

+186
-21
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package tests
2+
package sealedClasses
3+
4+
sealed trait A
5+
6+
sealed trait B1 extends A
7+
case class B2(a: Int) extends A
8+
case object B3 extends A
9+
class B4 extends A
10+
object B4 extends A
11+
object B5 extends A
12+
case class B6(a: Int) extends A
13+
case object B6 extends A
14+
15+
sealed trait C1 extends B1
16+
case class C2(a: Int) extends B1
17+
case object C3 extends B1
18+
class C4 extends B1
19+
object C4 extends B1
20+
object C5 extends B1
21+
case class C6(a: Int) extends B1
22+
case object C6 extends B1
23+
24+
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package dotty.dokka
2+
3+
import org.jetbrains.dokka.transformers.documentation.DocumentableTransformer
4+
import org.jetbrains.dokka.model.{ Modifier => _, _ }
5+
import collection.JavaConverters._
6+
import org.jetbrains.dokka.plugability.DokkaContext
7+
import org.jetbrains.dokka.model.properties._
8+
9+
import dotty.dokka.model._
10+
import dotty.dokka.model.api._
11+
12+
13+
class SealedMarksGraphTransformer(using context: DocContext) extends ModuleTransformer:
14+
override def apply(original: DModule): DModule =
15+
val sealedRelations = getSealedRelations(original.getPackages.get(0))
16+
original.updateMembers { m =>
17+
m.mapGraphEdges {
18+
case Edge(from @ LinkToType(_, fromDri, _), to @ LinkToType(_, toDri, _), _) =>
19+
val desc = if sealedRelations.contains(toDri) then "🔒" else ""
20+
Edge(from, to, desc)
21+
}
22+
}
23+
24+
private def getSealedRelations(c: Member): Set[DRI] =
25+
val selfMapping = if c.modifiers.contains(Modifier.Sealed) then Set(c.dri) else Set.empty
26+
c.allMembers.flatMap(getSealedRelations).toSet ++ selfMapping
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
package dotty.dokka.diagram
2+
3+
import dotty.dokka.ScaladocTest
4+
import dotty.dokka.Assertion.AfterDocumentablesTransformation
5+
import dotty.dokka.kUnit
6+
import dotty.dokka.model.api._
7+
import scala.jdk.CollectionConverters.{ListHasAsScala, SeqHasAsJava}
8+
import org.junit.Assert.{assertSame, assertTrue, assertEquals}
9+
10+
class HierarchyTest extends ScaladocTest("hierarchy"):
11+
override def assertions = Seq(
12+
AfterDocumentablesTransformation { m =>
13+
m.visitMembers { x =>
14+
if (x.getName == "C1") {
15+
assertEquals(List("A1", "A2[Int]", "A3[Int, String]", "Any", "B1", "B2", "B3", "Matchable", "Object"), x.getParentsAsStrings)
16+
assertEquals(List("B1", "B2", "B3"), x.getDirectParentsAsStrings)
17+
assertEquals(List("E1", "E2"), x.getKnownChildrenAsStrings)
18+
val graph = MemberExtension.getFrom(x).map(_.graph)
19+
assertTrue("Graph is empty!", graph.isDefined)
20+
assertEquals(
21+
Set(
22+
"Object" -> "Matchable",
23+
"Matchable" -> "Any",
24+
"Object" -> "Any",
25+
"A1" -> "Object",
26+
"A2[Int]" -> "Object",
27+
"A3[Int, String]" -> "Object",
28+
"B1" -> "Object",
29+
"B1" -> "A1",
30+
"B2" -> "Object",
31+
"B2" -> "A1",
32+
"B2" -> "A2[Int]",
33+
"B3" -> "Object",
34+
"B3" -> "A2[Int]",
35+
"B3" -> "A3[Int, String]",
36+
"C1[A, B, C]" -> "Object",
37+
"C1[A, B, C]" -> "B1",
38+
"C1[A, B, C]" -> "B2",
39+
"C1[A, B, C]" -> "B3",
40+
"E1" -> "C1[A, B, C]",
41+
"E2" -> "C1[A, B, C]"
42+
),
43+
graph.get.edges.map { case Edge(a, b, _) => (a.signature.getName, b.signature.getName) }.toSet
44+
)
45+
}
46+
if (x.getName == "E2") {
47+
assertEquals(List("A1", "A2[Int]", "A3[Int, String]", "A4", "Any", "B1", "B2", "B3", "C1[Int, Boolean, Any]", "D2[Int, Boolean]", "D3", "Matchable", "Object"), x.getParentsAsStrings)
48+
assertEquals(List("C1[Int, Boolean, Any]", "D2[Int, Boolean]", "D3"), x.getDirectParentsAsStrings)
49+
assertEquals(List.empty, x.getKnownChildrenAsStrings)
50+
val graph = MemberExtension.getFrom(x).map(_.graph)
51+
assertTrue("Graph is empty!", graph.isDefined)
52+
assertEquals(
53+
Set(
54+
"Object" -> "Any",
55+
"A1" -> "Object",
56+
"A2[Int]" -> "Object",
57+
"A3[Int, String]" -> "Object",
58+
"A4" -> "Object",
59+
"B1" -> "Object",
60+
"B1" -> "A1",
61+
"B2" -> "Object",
62+
"B2" -> "A1",
63+
"B2" -> "A2[Int]",
64+
"B3" -> "Object",
65+
"B3" -> "A2[Int]",
66+
"B3" -> "A3[Int, String]",
67+
"C1[Int, Boolean, Any]" -> "Object",
68+
"C1[Int, Boolean, Any]" -> "B1",
69+
"C1[Int, Boolean, Any]" -> "B2",
70+
"C1[Int, Boolean, Any]" -> "B3",
71+
"Object" -> "Matchable",
72+
"Matchable" -> "Any",
73+
"E2" -> "D2[Int, Boolean]",
74+
"E2" -> "D3",
75+
"D2[Int, Boolean]" -> "Object",
76+
"D3" -> "A4",
77+
"D3" -> "Object",
78+
"E2" -> "C1[Int, Boolean, Any]"
79+
),
80+
graph.get.edges.map { case Edge(a, b, _) => (a.signature.getName, b.signature.getName) }.toSet
81+
)
82+
}
83+
if (x.getName == "A2") {
84+
assertEquals(List("Any", "Matchable", "Object"), x.getParentsAsStrings)
85+
assertEquals(List.empty, x.getDirectParentsAsStrings)
86+
assertEquals(List("B2", "B3", "C1[A, B, C]", "E1", "E2"), x.getKnownChildrenAsStrings)
87+
val graph = MemberExtension.getFrom(x).map(_.graph)
88+
assertTrue("Graph is empty!", graph.isDefined)
89+
assertEquals(
90+
Set(
91+
"Object" -> "Matchable",
92+
"Matchable" -> "Any",
93+
"Object" -> "Any",
94+
"A2[T]" -> "Object",
95+
"B2" -> "A2[T]",
96+
"B3" -> "A2[T]",
97+
"C1[A, B, C]" -> "B2",
98+
"C1[A, B, C]" -> "B3",
99+
"E1" -> "C1[A, B, C]",
100+
"E2" -> "C1[A, B, C]"
101+
),
102+
graph.get.edges.map { case Edge(a, b, _) => (a.signature.getName, b.signature.getName) }.toSet
103+
)
104+
}
105+
}
106+
}
107+
)

scaladoc-testcases/src/tests/shadowingDRI.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@ class S:
77
class R:
88
def findThisDeclaration = 1
99

10-
given R: A[B] with {}
10+
given R: A[B] with {}

scaladoc/resources/dotty_res/scripts/ux.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,8 @@ function showGraph() {
9595

9696
g.edges().forEach(function(v) {
9797
g.setEdge(v, {
98-
arrowhead: "vee"
98+
arrowhead: "vee",
99+
label: g.edge(v).label
99100
});
100101
});
101102
render(inner, g);

scaladoc/src/dotty/tools/scaladoc/api.scala

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -126,17 +126,22 @@ extension (s: Signature)
126126
def join(a: Signature): Signature = s ++ a
127127

128128
case class LinkToType(signature: Signature, dri: DRI, kind: Kind)
129-
case class HierarchyGraph(edges: Seq[(LinkToType, LinkToType)]):
130-
private def vertecies: Seq[LinkToType] = edges.flatten((a, b) => Seq(a, b)).distinct
131-
def verteciesWithId: Map[LinkToType, Int] = vertecies.zipWithIndex.toMap
132-
def +(edge: (LinkToType, LinkToType)): HierarchyGraph = HierarchyGraph((edges :+ edge).distinct)
133-
def ++(edges: Seq[(LinkToType, LinkToType)]): HierarchyGraph = edges.foldLeft(this) {
129+
130+
case class Edge(from: LinkToType, to: LinkToType, pathDescription: String):
131+
def withDescription(desc: String) = copy(pathDescription = desc)
132+
extension (from: LinkToType) def to(to: LinkToType) = Edge(from, to, "")
133+
extension (edges: Seq[(LinkToType, LinkToType)]) def toEdges: Seq[Edge] = edges.map(_ to _)
134+
135+
case class HierarchyGraph(edges: Seq[Edge]):
136+
def vertecies: Seq[LinkToType] = edges.flatten { case Edge(a, b, _) => Seq(a, b) }.distinct
137+
val verteciesWithId: Map[LinkToType, Int] = vertecies.zipWithIndex.toMap
138+
def +(edge: Edge): HierarchyGraph = HierarchyGraph((edges :+ edge).distinct)
139+
def ++(edges: Seq[Edge]): HierarchyGraph = edges.foldLeft(this) {
134140
case (acc, edge) => acc + edge
135141
}
136142
object HierarchyGraph:
137143
def empty = HierarchyGraph(Seq.empty)
138-
def withEdges(edges: Seq[(LinkToType, LinkToType)]) = HierarchyGraph.empty ++ edges
139-
144+
def withEdges(edges: Seq[Edge]) = HierarchyGraph.empty ++ edges
140145

141146
case class Member(
142147
name: String,

scaladoc/src/dotty/tools/scaladoc/renderers/DotDiagramBuilder.scala

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@ object DotDiagramBuilder:
1515

1616
val vWithId = diagram.verteciesWithId
1717
val vertecies = vWithId.map { (vertex, id) =>
18-
s"""node${id} [id=node${id}, label="${getHtmlLabel(vertex, renderer)}", style="${getStyle(vertex)}"];\n"""
18+
s"""node${id} [id=node${id}, label="${getHtmlLabel(vertex, renderer, diagram.edges)}", style="${getStyle(vertex)}"];\n"""
1919
}.mkString
2020

21-
val edges = diagram.edges.map { (from, to) =>
22-
s"""node${vWithId(from)} -> node${vWithId(to)};\n"""
21+
val edges = diagram.edges.map { case Edge(from, to, description) =>
22+
s"""node${vWithId(from)} -> node${vWithId(to)} [label=""];\n"""
2323
}.mkString
2424

2525
s""" digraph g {
@@ -29,8 +29,9 @@ object DotDiagramBuilder:
2929
|}
3030
|""".stripMargin
3131

32-
private def getHtmlLabel(vertex: LinkToType, renderer: SignatureRenderer): String =
32+
private def getHtmlLabel(vertex: LinkToType, renderer: SignatureRenderer, edges: Seq[Edge]): String =
3333
span(style := "color: #FFFFFF;")(
34+
edges.find(_.to == vertex).fold("")(x => if x.pathDescription != "" then "sealed " else ""),
3435
vertex.kind.name,
3536
" ",
3637
vertex.signature.map(renderer.renderElementWith(_))

scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ trait ClassLikeSupport:
4848
signatureOnly: Boolean = false,
4949
modifiers: Seq[Modifier] = classDef.symbol.getExtraModifiers(),
5050
): Member =
51-
5251
def unpackTreeToClassDef(tree: Tree): ClassDef = tree match
5352
case tree: ClassDef => tree
5453
case TypeDef(_, tbt: TypeBoundsTree) => unpackTreeToClassDef(tbt.tpe.typeSymbol.tree)
@@ -73,14 +72,16 @@ trait ClassLikeSupport:
7372
}
7473
val selfSiangture: DSignature = typeForClass(classDef).asSignature
7574

76-
val graph = HierarchyGraph.withEdges(getSupertypesGraph(classDef,
77-
LinkToType(selfSiangture, classDef.symbol.dri, bareClasslikeKind(classDef.symbol))))
75+
val graph = HierarchyGraph.withEdges(
76+
getSupertypesGraph(classDef, LinkToType(selfSiangture, classDef.symbol.dri, bareClasslikeKind(classDef.symbol)))
77+
.toEdges
78+
)
7879

7980
val baseMember = mkMember(classDef.symbol, kindForClasslike(classDef), selfSiangture)(
80-
modifiers = modifiers,
81-
graph = graph,
82-
deprecated = classDef.symbol.isDeprecated()
83-
)
81+
modifiers = modifiers,
82+
graph = graph,
83+
deprecated = classDef.symbol.isDeprecated()
84+
)
8485

8586
if signatureOnly then baseMember else baseMember.copy(
8687
members = classDef.extractPatchedMembers,

scaladoc/src/dotty/tools/scaladoc/transformers/InheritanceInformationTransformer.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ class InheritanceInformationTransformer(using DocContext) extends (Module => Mod
77
original.updateMembers { m =>
88
val edges = getEdges(m.asLink.copy(kind = bareClasslikeKind(m.kind)), subtypes)
99
val st: Seq[LinkToType] = edges.map(_._1).distinct
10-
m.withKnownChildren(st).withNewGraphEdges(edges)
10+
m.withKnownChildren(st).withNewGraphEdges(edges.toEdges)
1111
}
1212

1313
private def getEdges(ltt: LinkToType, subtypes: Map[DRI, Seq[LinkToType]]): Seq[(LinkToType, LinkToType)] =

0 commit comments

Comments
 (0)