Skip to content

Commit 8e39b71

Browse files
committed
Fix repeated traversal of packages when generating docs (5x speedup)
1 parent bc594c8 commit 8e39b71

File tree

8 files changed

+151
-42
lines changed

8 files changed

+151
-42
lines changed

dottydoc/jvm/src/dotty/tools/dottydoc/core/Phases.scala

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,22 @@ object Phases {
9494
var packages: Map[String, Package] = Map.empty
9595

9696
def addEntity(p: Package): Package = {
97+
def mergedChildren(x1s: List[Entity], x2s: List[Entity]): List[Entity] = {
98+
val (packs1, others1) = x1s.partition(_.kind == "package")
99+
val (packs2, others2) = x2s.partition(_.kind == "package")
100+
101+
val others = others1 ::: others2
102+
val packs = (packs1 ::: packs2).groupBy(_.path).map(_._2.head)
103+
104+
(others ++ packs).sortBy(_.name)
105+
}
106+
97107
val path = p.path.mkString(".")
98-
val newPack = packages.get(path).map { ex =>
99-
val children = (ex.children ::: p.children).distinct.sortBy(_.name)
100-
PackageImpl(p.name, children, p.path, None)
108+
val newPack = packages.get(path).map {
109+
case ex: PackageImpl =>
110+
if (!ex.comment.isDefined) ex.comment = p.comment
111+
ex.members = mergedChildren(ex.members, p.members)
112+
ex
101113
}.getOrElse(p)
102114

103115
packages = packages + (path -> newPack)

dottydoc/jvm/test/CompilerTest.scala renamed to dottydoc/jvm/test/BaseTest.scala

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package dottydoc
33

44
import dotc.core.Contexts
55
import Contexts.{ Context, ContextBase, FreshContext }
6+
import dotc.util.SourceFile
67
import dotc.core.Phases.Phase
78
import dotc.typer.FrontEnd
89
import dottydoc.core.Phases.DocPhase
@@ -34,17 +35,24 @@ trait DottyTest {
3435
Nil
3536
}
3637

37-
def checkCompile(source: String)(assertion: DocPhase => Unit): Unit = {
38+
def checkSource(source: String)(assertion: DocPhase => Unit): Unit = {
3839
val c = compilerWithChecker(assertion)
3940
c.rootContext(ctx)
4041
val run = c.newRun
4142
run.compile(source)
4243
}
4344

44-
def checkCompile(sources: List[String])(assertion: DocPhase => Unit): Unit = {
45+
def checkFiles(sources: List[String])(assertion: DocPhase => Unit): Unit = {
4546
val c = compilerWithChecker(assertion)
4647
c.rootContext(ctx)
4748
val run = c.newRun
4849
run.compile(sources)
4950
}
51+
52+
def checkSources(sourceFiles: List[SourceFile])(assertion: DocPhase => Unit): Unit = {
53+
val c = compilerWithChecker(assertion)
54+
c.rootContext(ctx)
55+
val run = c.newRun
56+
run.compileSources(sourceFiles)
57+
}
5058
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
package dotty.tools
2+
package dottydoc
3+
4+
import org.junit.Test
5+
import org.junit.Assert._
6+
7+
import dotc.util.SourceFile
8+
import model.internal._
9+
10+
class PackageStructure extends DottyTest {
11+
@Test def multipleCompilationUnits = {
12+
val source1 = new SourceFile(
13+
"<test>",
14+
"""
15+
|package scala
16+
|
17+
|trait A
18+
""".stripMargin
19+
)
20+
21+
val source2 = new SourceFile(
22+
"<test>",
23+
"""
24+
|package scala
25+
|
26+
|trait B
27+
""".stripMargin
28+
)
29+
30+
checkSources(source1 :: source2 :: Nil) { doc =>
31+
doc.packages("scala") match {
32+
case PackageImpl(_, List(tA, tB), _, _) =>
33+
assert(
34+
tA.name == "A" && tB.name == "B",
35+
s"trait A had name '${tA.name}' and trait B had name '${tB.name}'"
36+
)
37+
case _ => fail("Incorrect package structure after run")
38+
}
39+
}
40+
}
41+
42+
43+
@Test def multiplePackages = {
44+
val source1 = new SourceFile(
45+
"<test>",
46+
"""
47+
|package scala
48+
|package collection
49+
|
50+
|trait A
51+
""".stripMargin)
52+
53+
val source2 = new SourceFile(
54+
"<test>",
55+
"""
56+
|package scala
57+
|package collection
58+
|
59+
|trait B
60+
""".stripMargin)
61+
62+
checkSources(source1 :: source2 :: Nil) { doc =>
63+
doc.packages("scala") match {
64+
case PackageImpl(
65+
"scala",
66+
List(PackageImpl("scala.collection", List(tA, tB), _, _)),
67+
_, _
68+
) =>
69+
assert(
70+
tA.name == "A" && tB.name == "B",
71+
s"trait A had name '${tA.name}' and trait B had name '${tB.name}'"
72+
)
73+
74+
case _ =>
75+
fail(s"""Incorrect package structure for 'scala' package: ${doc.packages("scala")}""")
76+
}
77+
78+
doc.packages("scala.collection") match {
79+
case PackageImpl("scala.collection", List(tA, tB), _, _) =>
80+
assert(
81+
tA.name == "A" && tB.name == "B",
82+
s"trait A had name '${tA.name}' and trait B had name '${tB.name}'"
83+
)
84+
85+
case _ => fail("Incorrect package structure for 'scala.collection' package")
86+
}
87+
}
88+
}
89+
}

dottydoc/jvm/test/TestSimpleComments.scala renamed to dottydoc/jvm/test/SimpleComments.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class TestSimpleComments extends DottyTest {
1515
|trait HelloWorld
1616
""".stripMargin
1717

18-
checkCompile(source) { doc =>
18+
checkSource(source) { doc =>
1919
val traitCmt = doc
2020
.packages("scala")
2121
.children.find(_.path.mkString(".") == "scala.HelloWorld")

dottydoc/jvm/test/TestWhitelistedStdLib.scala

Lines changed: 0 additions & 17 deletions
This file was deleted.
Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,17 @@
11
package dotty.tools
22
package dottydoc
33

4-
import scala.io.Source
4+
import org.junit.Test
5+
import org.junit.Assert._
56

6-
object WhitelistedStandardLib extends DottyDoc {
7-
val files: List[String] = {
8-
val whitelist = "../../test/dotc/scala-collections.whitelist"
7+
class TestWhitelistedCollections extends DottyTest {
8+
@Test def arrayHasDocumentation =
9+
checkFiles(WhitelistedStandardLib.files) { doc =>
10+
val array = doc
11+
.packages("scala")
12+
.children.find(_.path.mkString(".") == "scala.Array")
13+
.get
914

10-
Source.fromFile(whitelist, "UTF8")
11-
.getLines()
12-
.map(_.trim) // allow identation
13-
.filter(!_.startsWith("#")) // allow comment lines prefixed by #
14-
.map(_.takeWhile(_ != '#').trim) // allow comments in the end of line
15-
.filter(_.nonEmpty)
16-
.filterNot(_.endsWith("package.scala"))
17-
.map("../." + _)
18-
.toList
19-
}
20-
21-
override def main(args: Array[String]) =
22-
super.main("-language:Scala2" +: files.toArray)
15+
assert(array.comment.get.body.length > 0)
16+
}
2317
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package dotty.tools
2+
package dottydoc
3+
4+
import scala.io.Source
5+
6+
object WhitelistedStandardLib extends DottyDoc {
7+
val files: List[String] = {
8+
val whitelist = "../../test/dotc/scala-collections.whitelist"
9+
10+
Source.fromFile(whitelist, "UTF8")
11+
.getLines()
12+
.map(_.trim) // allow identation
13+
.filter(!_.startsWith("#")) // allow comment lines prefixed by #
14+
.map(_.takeWhile(_ != '#').trim) // allow comments in the end of line
15+
.filter(_.nonEmpty)
16+
.filterNot(_.endsWith("package.scala"))
17+
.map("../." + _)
18+
.toList
19+
}
20+
21+
override def main(args: Array[String]) =
22+
super.main("-language:Scala2" +: files.toArray)
23+
}

dottydoc/shared/src/main/scala/dotty/tools/dottydoc/model/internal.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@ object internal {
1111

1212
final case class PackageImpl(
1313
name: String,
14-
members: List[Entity],
14+
var members: List[Entity],
1515
path: List[String],
1616
var comment: Option[Comment] = None
1717
) extends Package with Impl {
18-
val children: List[Entity with Members] =
18+
def children: List[Entity with Members] =
1919
members.collect { case x: Entity with Members => x }
2020
}
2121

0 commit comments

Comments
 (0)