diff options
author | Felix Mulder <felix.mulder@gmail.com> | 2017-01-21 19:56:10 +0100 |
---|---|---|
committer | Felix Mulder <felix.mulder@gmail.com> | 2017-01-31 14:32:40 +0100 |
commit | 3e9451d79b3e6845c4b1c0906401108a609eddf8 (patch) | |
tree | 66a01844ca1043f5dc5b16ea0c8d7da93d70479f /doc-tool/src/dotty/tools/dottydoc/core | |
parent | 384f5a0dba5c2102327015c67781462ba475e43a (diff) | |
download | dotty-3e9451d79b3e6845c4b1c0906401108a609eddf8.tar.gz dotty-3e9451d79b3e6845c4b1c0906401108a609eddf8.tar.bz2 dotty-3e9451d79b3e6845c4b1c0906401108a609eddf8.zip |
Fix insertion of package nodes in doc AST
Diffstat (limited to 'doc-tool/src/dotty/tools/dottydoc/core')
3 files changed, 105 insertions, 47 deletions
diff --git a/doc-tool/src/dotty/tools/dottydoc/core/DocASTPhase.scala b/doc-tool/src/dotty/tools/dottydoc/core/DocASTPhase.scala index 411818614..72953b5a8 100644 --- a/doc-tool/src/dotty/tools/dottydoc/core/DocASTPhase.scala +++ b/doc-tool/src/dotty/tools/dottydoc/core/DocASTPhase.scala @@ -23,7 +23,7 @@ class DocASTPhase extends Phase { import util.traversing._ import util.internal.setters._ - def phaseName = "docphase" + def phaseName = "docASTPhase" /** Build documentation hierarchy from existing tree */ def collect(tree: Tree, prev: List[String] = Nil)(implicit ctx: Context): Entity = { @@ -64,7 +64,6 @@ class DocASTPhase extends Phase { // don't add privates, synthetics or class parameters (i.e. value class constructor val) val vals = sym.info.fields.filterNot(_.symbol.is(Flags.ParamAccessor | Flags.Private | Flags.Synthetic)).map { value => - println(value + " " + value.symbol.flags) val kind = if (value.symbol.is(Flags.Mutable)) "var" else "val" ValImpl( value.symbol, @@ -87,7 +86,7 @@ class DocASTPhase extends Phase { /** package */ case pd @ PackageDef(pid, st) => val pkgPath = path(pd.symbol) - addEntity(PackageImpl(pd.symbol, annotations(pd.symbol), pd.symbol.showFullName, collectEntityMembers(st, pkgPath), pkgPath)) + addPackage(PackageImpl(pd.symbol, annotations(pd.symbol), pd.symbol.showFullName, collectEntityMembers(st, pkgPath), pkgPath)) /** type alias */ case t: TypeDef if !t.isClassDef => @@ -111,7 +110,7 @@ class DocASTPhase extends Phase { /** class / case class */ case c @ TypeDef(n, rhs) if c.symbol.isClass => //TODO: should not `collectMember` from `rhs` - instead: get from symbol, will get inherited members as well - (c.symbol, annotations(c.symbol), n.show, collectMembers(rhs), flags(c), path(c.symbol), typeParams(c.symbol), constructors(c.symbol), superTypes(c), None, Nil) match { + (c.symbol, annotations(c.symbol), n.show, collectMembers(rhs), flags(c), path(c.symbol), typeParams(c.symbol), constructors(c.symbol), superTypes(c), None, Nil, NonEntity) match { case x if c.symbol.is(Flags.CaseClass) => CaseClassImpl.tupled(x) case x => ClassImpl.tupled(x) } @@ -132,29 +131,90 @@ class DocASTPhase extends Phase { } } - var packages: Map[String, Package] = Map.empty + var packages: Map[String, PackageImpl] = Map.empty - def addEntity(p: Package): Package = { - def mergedChildren(x1s: List[Entity], x2s: List[Entity]): List[Entity] = { - val (packs1, others1) = x1s.partition(_.kind == "package") - val (packs2, others2) = x2s.partition(_.kind == "package") + def addPackage(newPkg: PackageImpl): Package = { + def mergeMembers(newPkg: PackageImpl, oldPkg: PackageImpl): Unit = { + val othersNew = newPkg.members.filterNot(_.kind == "package") + val (oldPacks, othersOld) = oldPkg.members.partition(_.kind == "package") - val others = others1 ::: others2 - val packs = (packs1 ::: packs2).groupBy(_.path).map(_._2.head) + val others = othersNew ::: othersOld + // here we can just choose the old packs, since we're recursively (bottom up) + // discovering the tree, we should have met the child packages first, as + // such - they were already inserted into the tree + val newMembers = (others ++ oldPacks) - (others ++ packs).sortBy(_.name) + oldPkg.members = newMembers } - val path = p.path.mkString(".") - val newPack = packages.get(path).map { - case ex: PackageImpl => - if (!ex.comment.isDefined) ex.comment = p.comment - ex.members = mergedChildren(ex.members, p.members) - ex - }.getOrElse(p) + // This function mutates packages in place as not to create any orphaned references + def mergedPackages(old: PackageImpl, newPkg: PackageImpl): PackageImpl = { + if (old.symbol eq NoSymbol) old.symbol = newPkg.symbol + if (old.annotations.isEmpty) old.annotations = newPkg.annotations + mergeMembers(newPkg, old) + if (old.superTypes.isEmpty) old.superTypes = newPkg.superTypes + if (!old.comment.isDefined) old.comment = newPkg.comment + old + } + + def insertOrModifyRoot(): PackageImpl = { + val modifiedPkg = + packages + .get(newPkg.name) + .map(mergedPackages(_, newPkg)) + .getOrElse(newPkg) + + packages = packages + (modifiedPkg.name -> modifiedPkg) + modifiedPkg + } - packages = packages + (path -> newPack) - newPack + // This function inserts a package by creating empty packages to the point + // where it can insert the supplied package `newPkg`. + def createAndInsert(currentPkg: PackageImpl, path: List[String]): PackageImpl = { + (path: @unchecked) match { + case x :: Nil => { + val existingPkg = currentPkg.members.collect { + case p: PackageImpl if p.name == newPkg.name => p + }.headOption + + if (existingPkg.isDefined) mergedPackages(existingPkg.get, newPkg) + else { + currentPkg.members = newPkg :: currentPkg.members + newPkg + } + } + case x :: xs => { + val subPkg = s"${currentPkg.name}.$x" + val existingPkg = currentPkg.members.collect { + case p: PackageImpl if p.name == subPkg => p + }.headOption + + if (existingPkg.isDefined) createAndInsert(existingPkg.get, xs) + else { + val newEmpty = EmptyPackage(currentPkg.path :+ x, subPkg) + packages = packages + (subPkg -> newEmpty) + currentPkg.members = newEmpty :: currentPkg.members + createAndInsert(newEmpty, xs) + } + } + } + } + + val path = newPkg.path + if (path.length == 1) + insertOrModifyRoot() + else if (packages.contains(newPkg.name)) + mergedPackages(packages(newPkg.name), newPkg) + else { + val root = packages.get(path.head) + + if (root.isDefined) createAndInsert(root.get, newPkg.path.drop(1)) + else { + val newEmpty = EmptyPackage(List(path.head), path.head) + packages = packages + (path.head -> newEmpty) + createAndInsert(newEmpty, newPkg.path.drop(1)) + } + } } private[this] var totalRuns = 0 diff --git a/doc-tool/src/dotty/tools/dottydoc/core/MiniPhaseTransform.scala b/doc-tool/src/dotty/tools/dottydoc/core/MiniPhaseTransform.scala index 1cfcec09a..4980cad92 100644 --- a/doc-tool/src/dotty/tools/dottydoc/core/MiniPhaseTransform.scala +++ b/doc-tool/src/dotty/tools/dottydoc/core/MiniPhaseTransform.scala @@ -9,6 +9,7 @@ import dotc.core.Phases.Phase import model._ import model.internal._ import util.syntax._ +import util.traversing._ object transform { /** @@ -48,30 +49,13 @@ object transform { override def runOn(units: List[CompilationUnit])(implicit ctx: Context): List[CompilationUnit] = { for { - rootName <- rootPackages + rootName <- rootPackages(ctx.docbase.packages) pack = ctx.docbase.packages(rootName) transformed = performPackageTransform(pack) } yield ctx.docbase.packagesMutable(rootName) = transformed super.runOn(units) } - private def rootPackages(implicit ctx: Context): List[String] = { - var currentDepth = Int.MaxValue - var packs = List.empty[String] - - for (key <- ctx.docbase.packages.keys) { - val keyDepth = key.split("\\.").length - packs = - if (keyDepth < currentDepth) { - currentDepth = keyDepth - key :: Nil - } else if (keyDepth == currentDepth) { - key :: packs - } else packs - } - packs - } - private def performPackageTransform(pack: Package)(implicit ctx: Context): Package = { def transformEntity[E <: Entity](e: E, f: DocMiniPhase => E => E)(createNew: E => E): Entity = { val transformedEntity = transformations.foldLeft(e) { case (oldE, transf) => @@ -91,7 +75,8 @@ object transform { p.members.map(traverse).filterNot(_ eq NonEntity), p.path, p.superTypes, - p.comment + p.comment, + p.parent ) // Update reference in context to newPackage @@ -107,7 +92,8 @@ object transform { t.name, t.path, t.alias, - t.comment + t.comment, + t.parent ) } case c: Class => transformEntity(c, _.classTransformation) { cls => @@ -122,7 +108,8 @@ object transform { cls.constructors, cls.superTypes, cls.comment, - cls.companionPath + cls.companionPath, + cls.parent ) } case cc: CaseClass => transformEntity(cc, _.caseClassTransformation) { cc => @@ -137,7 +124,8 @@ object transform { cc.constructors, cc.superTypes, cc.comment, - cc.companionPath + cc.companionPath, + cc.parent ) } case trt: Trait => transformEntity(trt, _.traitTransformation) { trt => @@ -152,7 +140,8 @@ object transform { trt.traitParams, trt.superTypes, trt.comment, - trt.companionPath + trt.companionPath, + trt.parent ) } case obj: Object => transformEntity(obj, _.objectTransformation) { obj => @@ -165,7 +154,8 @@ object transform { obj.path, obj.superTypes, obj.comment, - obj.companionPath + obj.companionPath, + obj.parent ) } case df: Def => transformEntity(df, _.defTransformation) { df => @@ -179,7 +169,8 @@ object transform { df.typeParams, df.paramLists, df.comment, - df.implicitlyAddedFrom + df.implicitlyAddedFrom, + df.parent ) } case vl: Val => transformEntity(vl, _.valTransformation) { vl => @@ -192,7 +183,8 @@ object transform { vl.returnValue, vl.kind, vl.comment, - vl.implicitlyAddedFrom + vl.implicitlyAddedFrom, + vl.parent ) } } diff --git a/doc-tool/src/dotty/tools/dottydoc/core/TypeLinkingPhases.scala b/doc-tool/src/dotty/tools/dottydoc/core/TypeLinkingPhases.scala index 245db060d..02f6ccb97 100644 --- a/doc-tool/src/dotty/tools/dottydoc/core/TypeLinkingPhases.scala +++ b/doc-tool/src/dotty/tools/dottydoc/core/TypeLinkingPhases.scala @@ -82,6 +82,12 @@ trait TypeLinker extends MemberLookup { target match { case Some(target: Package) => MaterializedLink(title, target.path.mkString("/") + "/index.html") + case Some(target: TypeAlias) => + MaterializedLink(title, target.parent.path.mkString("/") + ".html#" + target.signature) + case Some(target: Def) => + MaterializedLink(title, target.parent.path.mkString("/") + ".html#" + target.signature) + case Some(target: Val) => + MaterializedLink(title, target.parent.path.mkString("/") + ".html#" + target.signature) case Some(target) => MaterializedLink(title, target.path.mkString("/") + ".html") case none => |