From 18c673073c29641cdd8386253ee34d7e4007b3b1 Mon Sep 17 00:00:00 2001 From: Felix Mulder Date: Tue, 14 Feb 2017 21:31:13 +0100 Subject: Add some basic stats to ddoc --- .../src/dotty/tools/dottydoc/DocCompiler.scala | 3 +- doc-tool/src/dotty/tools/dottydoc/DocDriver.scala | 5 +- .../tools/dottydoc/core/ContextDottydoc.scala | 86 +++++++- .../dotty/tools/dottydoc/core/DocASTPhase.scala | 5 +- .../dotty/tools/dottydoc/core/DocstringPhase.scala | 1 + .../tools/dottydoc/core/MiniPhaseTransform.scala | 231 -------------------- .../tools/dottydoc/core/StatisticsPhase.scala | 156 ++++++++++++++ .../src/dotty/tools/dottydoc/core/transform.scala | 232 +++++++++++++++++++++ .../src/dotty/tools/dottydoc/util/traversing.scala | 4 +- 9 files changed, 483 insertions(+), 240 deletions(-) delete mode 100644 doc-tool/src/dotty/tools/dottydoc/core/MiniPhaseTransform.scala create mode 100644 doc-tool/src/dotty/tools/dottydoc/core/StatisticsPhase.scala create mode 100644 doc-tool/src/dotty/tools/dottydoc/core/transform.scala (limited to 'doc-tool') diff --git a/doc-tool/src/dotty/tools/dottydoc/DocCompiler.scala b/doc-tool/src/dotty/tools/dottydoc/DocCompiler.scala index 708c26cc0..c5d20d30b 100644 --- a/doc-tool/src/dotty/tools/dottydoc/DocCompiler.scala +++ b/doc-tool/src/dotty/tools/dottydoc/DocCompiler.scala @@ -32,6 +32,7 @@ class DocCompiler extends Compiler { new LinkSuperTypes, new LinkCompanions, new AlternateConstructors, - new SortMembers)) + new SortMembers)), + List(new StatisticsPhase) ) } diff --git a/doc-tool/src/dotty/tools/dottydoc/DocDriver.scala b/doc-tool/src/dotty/tools/dottydoc/DocDriver.scala index 515de9ae9..1434d5a49 100644 --- a/doc-tool/src/dotty/tools/dottydoc/DocDriver.scala +++ b/doc-tool/src/dotty/tools/dottydoc/DocDriver.scala @@ -9,6 +9,7 @@ import model.Package import dotc.config._ import dotc.core.Comments.ContextDoc import staticsite.Site +import dotc.printing.Highlighting._ /** `DocDriver` implements the main entry point to the Dotty documentation * tool. It's methods are used by the external scala and java APIs. @@ -43,16 +44,18 @@ class DocDriver extends Driver { implicit val (filesToDocument, ctx) = setup(args, initCtx.fresh) val reporter = doCompile(newCompiler(ctx), filesToDocument)(ctx) val siteRoot = new java.io.File(ctx.settings.siteRoot.value) + val projectName = ctx.settings.projectName.value if (!siteRoot.exists || !siteRoot.isDirectory) ctx.error(s"Site root does not exist: $siteRoot") else { - Site(siteRoot, ctx.settings.projectName.value, ctx.docbase.packages) + Site(siteRoot, projectName, ctx.docbase.packages) .generateApiDocs() .copyStaticFiles() .generateHtmlFiles() .generateBlog() + ctx.docbase.printSummary() System.exit(if (reporter.hasErrors) 1 else 0) } } diff --git a/doc-tool/src/dotty/tools/dottydoc/core/ContextDottydoc.scala b/doc-tool/src/dotty/tools/dottydoc/core/ContextDottydoc.scala index 16f0776fa..8f463833d 100644 --- a/doc-tool/src/dotty/tools/dottydoc/core/ContextDottydoc.scala +++ b/doc-tool/src/dotty/tools/dottydoc/core/ContextDottydoc.scala @@ -2,9 +2,12 @@ package dotty.tools package dottydoc package core -import dotc.core.Symbols.Symbol +import dotc.core.Symbols._ +import dotc.core.Flags._ +import dotc.core.Decorators._ import dotc.core.Comments.ContextDocstrings -import model.Package +import model.{ Package, Entity } +import model.comment.Comment import dotc.core.Contexts.Context import dotc.printing.Highlighting._ @@ -17,6 +20,12 @@ class ContextDottydoc extends ContextDocstrings { def packages: Map[String, Package] = _packages.toMap def packagesMutable: mutable.Map[String, Package] = _packages + private[this] var _statistics: Map[String, Statistics] = Map.empty + def registerStatistics(pkgName: String, stat: Statistics): Unit = + _statistics = _statistics + (pkgName -> stat) + + def statistics: Map[String, Statistics] = _statistics + /** Should perhaps factorize this into caches that get flushed */ private var _defs: Map[Symbol, Set[Symbol]] = Map.empty def defs(sym: Symbol): Set[Symbol] = _defs.get(sym).getOrElse(Set.empty) @@ -49,4 +58,77 @@ class ContextDottydoc extends ContextDocstrings { }.toString, pos) def debug(msg: String)(implicit ctx: Context): Unit = debug(msg, NoSourcePosition) + + def printSummary()(implicit ctx: Context): Unit = { + def colored(part: Int, total: Int) = + if (total == 0) "0" + else { + val percentage = (part * 100.0 / total).toInt + val str = s"$part/$total ($percentage%)" + + if (percentage > 75) Green(str) + else if (percentage > 50) Yellow(str) + else Red(str) + } + + val totalEntities = statistics.totalEntities + + val projectName = ctx.settings.projectName.value + val warningsText = + if (ctx.reporter.hasWarnings) + s"total warnings with regards to compilation and documentation: ${ctx.reporter.warningCount}" + else "" + + val api = statistics.values.iterator.map(_.api).foldLeft(Counters(0,0,0,0,0,0))(_ merge _) + val internalApi = statistics.values.iterator.map(_.internalApi).foldLeft(Counters(0,0,0,0,0,0))(_ merge _) + + val apiSummary = (for { + (pkgName, stat) <- statistics.toList.sortBy(_._1) + } yield { + val pub = colored(stat.api.publicDocstrings, stat.api.publicEntities) + val pro = colored(stat.api.protectedDocstrings, stat.api.protectedEntities) + s"""|package $pkgName + |${Blue("-" * ctx.settings.pageWidth.value)} + |public: $pub \t protected: $pro + |""".stripMargin + }).mkString("\n") + + val internalSummary = (for { + (pkgName, stat) <- statistics.toList.sortBy(_._1) + } yield { + val pub = colored(stat.internalApi.publicDocstrings, stat.internalApi.publicEntities) + val pro = colored(stat.internalApi.protectedDocstrings, stat.internalApi.protectedEntities) + val pri = colored(stat.internalApi.privateDocstrings, stat.internalApi.privateEntities) + s"""|package $pkgName + |${Blue("-" * ctx.settings.pageWidth.value)} + |public: $pub \t protected: $pro \t private: $pri + |""".stripMargin + }).mkString("\n") + + ctx.echo { + s"""|${Blue("=" * ctx.settings.pageWidth.value)} + |Dottydoc summary report for project `$projectName` + |${Blue("=" * ctx.settings.pageWidth.value)} + |Documented members in public API: + | + |$apiSummary + | + |Summary: + | + |public members with docstrings: ${colored(api.publicDocstrings, api.publicEntities)} + |${hl"${"protected"}"} members with docstrings: ${colored(api.protectedDocstrings, api.protectedEntities)} + |${Blue("=" * ctx.settings.pageWidth.value)} + | + |Documented members in internal API: + | + |$internalSummary + | + |Summary internal API: + | + |public members with docstrings: ${colored(internalApi.publicDocstrings, internalApi.publicEntities)} + |${hl"${"protected"}"} members with docstrings: ${colored(internalApi.protectedDocstrings, internalApi.protectedEntities)} + |${hl"${"private"}"} members with docstrings: ${colored(internalApi.privateDocstrings, internalApi.privateEntities)} + |$warningsText""".stripMargin + } + } } diff --git a/doc-tool/src/dotty/tools/dottydoc/core/DocASTPhase.scala b/doc-tool/src/dotty/tools/dottydoc/core/DocASTPhase.scala index 460566838..7f44c5656 100644 --- a/doc-tool/src/dotty/tools/dottydoc/core/DocASTPhase.scala +++ b/doc-tool/src/dotty/tools/dottydoc/core/DocASTPhase.scala @@ -226,7 +226,7 @@ class DocASTPhase extends Phase { override def run(implicit ctx: Context): Unit = { currentRun += 1 - ctx.docbase.echo(s"Compiling ($currentRun/$totalRuns): ${ctx.compilationUnit.source.file.name}") + ctx.echo(s"Compiling ($currentRun/$totalRuns): ${ctx.compilationUnit.source.file.name}") collect(ctx.compilationUnit.tpdTree) // Will put packages in `packages` var } @@ -237,8 +237,7 @@ class DocASTPhase extends Phase { // (2) Set parents of entities, needed for linking for { - parentName <- rootPackages(packages) - parent = packages(parentName) + parent <- rootPackages(packages) child <- parent.members } setParent(child, to = parent) diff --git a/doc-tool/src/dotty/tools/dottydoc/core/DocstringPhase.scala b/doc-tool/src/dotty/tools/dottydoc/core/DocstringPhase.scala index 3de8f68f7..2471e9220 100644 --- a/doc-tool/src/dotty/tools/dottydoc/core/DocstringPhase.scala +++ b/doc-tool/src/dotty/tools/dottydoc/core/DocstringPhase.scala @@ -14,6 +14,7 @@ import util.syntax._ /** Phase to add docstrings to the Dottydoc AST */ class DocstringPhase extends DocMiniPhase with CommentParser with CommentCleaner { + private def getComment(sym: Symbol)(implicit ctx: Context): Option[CompilerComment] = ctx.docbase.docstring(sym) .orElse { diff --git a/doc-tool/src/dotty/tools/dottydoc/core/MiniPhaseTransform.scala b/doc-tool/src/dotty/tools/dottydoc/core/MiniPhaseTransform.scala deleted file mode 100644 index 1f30e089d..000000000 --- a/doc-tool/src/dotty/tools/dottydoc/core/MiniPhaseTransform.scala +++ /dev/null @@ -1,231 +0,0 @@ -package dotty.tools -package dottydoc -package core - -import dotc.CompilationUnit -import dotc.core.Contexts.Context -import dotc.core.Comments.ContextDocstrings -import dotc.core.Phases.Phase -import model._ -import model.internal._ -import util.syntax._ -import util.traversing._ - -object transform { - /** - * The idea behind DocMiniTransformations is to fuse transformations to the - * doc AST, much like `MiniPhaseTransform` in dotty core - but in a much more - * simple implementation - * - * Usage - * ----- - * - * Create a `DocMiniPhase` which overrides the relevant method: - * - * ``` - * override def transformDef(implicit ctx: Context) = { - * case x if shouldTransform(x) => x.copy(newValue = ...) - * } - * ``` - * - * On each node in the AST, the appropriate method in `DocMiniPhase` will be - * called in the order that they are supplied in - * `DocMiniphaseTransformations`. - * - * There won't be a match-error as `transformX` is composed with an - * `identity` function. - * - * The transformations in `DocMiniTransformations` will apply transformations - * to all nodes - this means that you do _not_ need to transform children in - * `transformPackage`, because `transformX` will be called for the relevant - * children. If you want to add children to `Package` you need to do that in - * `transformPackage`, these additions will be persisted. - * - * Deleting nodes in the AST - * ------------------------- - * To delete a node in the AST, simply return `NonEntity` from transforming method - */ - abstract class DocMiniTransformations(transformations: List[DocMiniPhase]) extends Phase { - - override def runOn(units: List[CompilationUnit])(implicit ctx: Context): List[CompilationUnit] = { - for { - rootName <- rootPackages(ctx.docbase.packages) - pack = ctx.docbase.packages(rootName) - transformed = performPackageTransform(pack) - } yield ctx.docbase.packagesMutable(rootName) = transformed - super.runOn(units) - } - - 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) => - f(transf)(oldE) - } - - if (transformedEntity eq NonEntity) NonEntity - else createNew(transformedEntity) - } - - def traverse(ent: Entity): Entity = ent match { - case p: Package => transformEntity(p, _.packageTransformation) { p => - val newPackage = PackageImpl( - p.symbol, - p.annotations, - p.name, - p.members.map(traverse).filterNot(_ eq NonEntity), - p.path, - p.superTypes, - p.comment, - p.parent - ) - - // Update reference in context to newPackage - ctx.docbase.packagesMutable += (newPackage.path.mkString(".") -> newPackage) - - newPackage - } - case t: TypeAlias => transformEntity(t, _.typeAliasTransformation) { t => - TypeAliasImpl( - t.symbol, - t.annotations, - t.modifiers, - t.name, - t.path, - t.alias, - t.comment, - t.parent - ) - } - case c: Class => transformEntity(c, _.classTransformation) { cls => - ClassImpl( - cls.symbol, - cls.annotations, - cls.name, - cls.members.map(traverse).filterNot(_ eq NonEntity), - cls.modifiers, - cls.path, - cls.typeParams, - cls.constructors, - cls.superTypes, - cls.comment, - cls.companionPath, - cls.parent - ) - } - case cc: CaseClass => transformEntity(cc, _.caseClassTransformation) { cc => - CaseClassImpl( - cc.symbol, - cc.annotations, - cc.name, - cc.members.map(traverse).filterNot(_ eq NonEntity), - cc.modifiers, - cc.path, - cc.typeParams, - cc.constructors, - cc.superTypes, - cc.comment, - cc.companionPath, - cc.parent - ) - } - case trt: Trait => transformEntity(trt, _.traitTransformation) { trt => - TraitImpl( - trt.symbol, - trt.annotations, - trt.name, - trt.members.map(traverse).filterNot(_ eq NonEntity), - trt.modifiers, - trt.path, - trt.typeParams, - trt.traitParams, - trt.superTypes, - trt.comment, - trt.companionPath, - trt.parent - ) - } - case obj: Object => transformEntity(obj, _.objectTransformation) { obj => - ObjectImpl( - obj.symbol, - obj.annotations, - obj.name, - obj.members.map(traverse).filterNot(_ eq NonEntity), - obj.modifiers, - obj.path, - obj.superTypes, - obj.comment, - obj.companionPath, - obj.parent - ) - } - case df: Def => transformEntity(df, _.defTransformation) { df => - DefImpl( - df.symbol, - df.annotations, - df.name, - df.modifiers, - df.path, - df.returnValue, - df.typeParams, - df.paramLists, - df.comment, - df.implicitlyAddedFrom, - df.parent - ) - } - case vl: Val => transformEntity(vl, _.valTransformation) { vl => - ValImpl( - vl.symbol, - vl.annotations, - vl.name, - vl.modifiers, - vl.path, - vl.returnValue, - vl.kind, - vl.comment, - vl.implicitlyAddedFrom, - vl.parent - ) - } - } - - traverse(pack).asInstanceOf[Package] - } - - override def run(implicit ctx: Context): Unit = () - } - - object DocMiniTransformations { - private var previousPhase = 0 - def apply(transformations: DocMiniPhase*) = - new DocMiniTransformations(transformations.toList) { - val packages = Map.empty[String, Package] - - def phaseName = s"MiniTransformation${ previousPhase += 1 }" - } - } - - trait DocMiniPhase { phase => - private def identity[E]: PartialFunction[E, E] = { - case id: E @unchecked => id - } - - def transformPackage(implicit ctx: Context): PartialFunction[Package, Package] = identity - def transformTypeAlias(implicit ctx: Context): PartialFunction[TypeAlias, TypeAlias] = identity - def transformClass(implicit ctx: Context): PartialFunction[Class, Class] = identity - def transformCaseClass(implicit ctx: Context): PartialFunction[CaseClass, CaseClass] = identity - def transformTrait(implicit ctx: Context): PartialFunction[Trait, Trait] = identity - def transformObject(implicit ctx: Context): PartialFunction[Object, Object] = identity - def transformDef(implicit ctx: Context): PartialFunction[Def, Def] = identity - def transformVal(implicit ctx: Context): PartialFunction[Val, Val] = identity - - private[transform] def packageTransformation(p: Package)(implicit ctx: Context) = (transformPackage orElse identity)(p) - private[transform] def typeAliasTransformation(alias: TypeAlias)(implicit ctx: Context) = (transformTypeAlias orElse identity)(alias) - private[transform] def classTransformation(cls: Class)(implicit ctx: Context) = (transformClass orElse identity)(cls) - private[transform] def caseClassTransformation(cc: CaseClass)(implicit ctx: Context) = (transformCaseClass orElse identity)(cc) - private[transform] def traitTransformation(trt: Trait)(implicit ctx: Context) = (transformTrait orElse identity)(trt) - private[transform] def objectTransformation(obj: Object)(implicit ctx: Context) = (transformObject orElse identity)(obj) - private[transform] def defTransformation(df: Def)(implicit ctx: Context) = (transformDef orElse identity)(df) - private[transform] def valTransformation(vl: Val)(implicit ctx: Context) = (transformVal orElse identity)(vl) - } -} diff --git a/doc-tool/src/dotty/tools/dottydoc/core/StatisticsPhase.scala b/doc-tool/src/dotty/tools/dottydoc/core/StatisticsPhase.scala new file mode 100644 index 000000000..e7f9a9ec7 --- /dev/null +++ b/doc-tool/src/dotty/tools/dottydoc/core/StatisticsPhase.scala @@ -0,0 +1,156 @@ +package dotty.tools +package dottydoc +package core + +import dotc.core.Phases.Phase +import dotc.core.Contexts.Context +import dotc.core.Symbols.Symbol +import dotc.core.Decorators._ +import dotc.core.Flags._ +import dotc.CompilationUnit +import dottydoc.util.syntax._ +import dottydoc.util.traversing._ + +import model._ + +object Statistics { + implicit class MapTotals(val map: Map[String, Statistics]) extends AnyVal { + def totalEntities = + map.values.foldLeft(0)(_ + _.totalEntities) + } +} + +case class Statistics(pkgName: String, api: Counters, internalApi: Counters) { + def totalEntities = + api.totalEntities + internalApi.totalEntities + + def totalDocstrings = + api.totalDocstrings + internalApi.totalDocstrings +} + +case class Counters( + publicEntities: Int, + privateEntities: Int, + protectedEntities: Int, + + publicDocstrings: Int, + privateDocstrings: Int, + protectedDocstrings: Int +) { + def totalEntities = + publicEntities + privateEntities + protectedEntities + + def totalDocstrings = + publicDocstrings + privateDocstrings + protectedDocstrings + + def merge(o: Counters): Counters = Counters( + publicEntities + o.publicEntities, + privateEntities + o.privateEntities, + protectedEntities + o.protectedEntities, + publicDocstrings + o.publicDocstrings, + privateDocstrings + o.privateDocstrings, + protectedDocstrings + o.protectedDocstrings + ) +} + +class StatisticsPhase extends Phase { + + def phaseName = "StatisticsPhase" + + override def run(implicit ctx: Context): Unit = () + + override def runOn(units: List[CompilationUnit])(implicit ctx: Context): List[CompilationUnit] = { + for { + (pkgName, pack) <- ctx.docbase.packages + externalApi = collectPublicStats(pack) + internalApi = collectInternalStats(pack) + stats = Statistics(pkgName, externalApi, internalApi) + } ctx.docbase.registerStatistics(pkgName, stats) + + units + } + + def collectPublicStats(pack: Package)(implicit ctx: Context): Counters = { + var publicEntities: Int = 0 + var protectedEntities: Int = 0 + var publicDocstrings: Int = 0 + var protectedDocstrings: Int = 0 + + if (pack.comment.isDefined) { + publicEntities += 1 + publicDocstrings += 1 + } + + def doCount(sym: Symbol, comment: Int): Unit = + if (!sym.is(Protected)) { + publicEntities += 1 + publicDocstrings += comment + } + else { + protectedEntities += 1 + protectedDocstrings += comment + } + + + def recur(e: Entity, reachable: Boolean): Unit = { + val isVisible = !e.symbol.is(Private) && !e.symbol.privateWithin.exists + val shouldCount = isVisible && reachable + e match { + case e: Package => () + case e: Entity with Members => if (shouldCount) { + doCount(e.symbol, if (e.comment.isDefined) 1 else 0) + e.members.foreach { c => + if (!(e.symbol.is(Final) && c.symbol.is(Protected))) recur(c, true) + } + } + case e => + if (shouldCount) doCount(e.symbol, if (e.comment.isDefined) 1 else 0) + } + } + + pack.members.foreach(recur(_, true)) + Counters(publicEntities, 0, protectedEntities, publicDocstrings, 0, protectedDocstrings) + } + + def collectInternalStats(pack: Package)(implicit ctx: Context): Counters = { + var publicEntities: Int = 0 + var privateEntities: Int = 0 + var protectedEntities: Int = 0 + var publicDocstrings: Int = 0 + var privateDocstrings: Int = 0 + var protectedDocstrings: Int = 0 + + def doCount(sym: Symbol, comment: Int): Unit = + if (sym.is(Private)) { + privateEntities += 1 + privateDocstrings += comment + } + else if (!sym.is(Protected)) { + publicEntities += 1 + publicDocstrings += comment + } + else { + protectedEntities += 1 + protectedDocstrings += comment + } + + + def recur(e: Entity, reachable: Boolean): Unit = { + val internal = !reachable || e.symbol.is(Private) || e.symbol.privateWithin.exists + e match { + case _: Package => () + case e: Entity with Members => + e.members.foreach { c => + val childIsInternal = !internal || (e.symbol.is(Final) && c.symbol.is(Protected)) + recur(c, childIsInternal) + } + if (internal) doCount(e.symbol, if (e.comment.isDefined) 1 else 0) + case _ => + if (internal) doCount(e.symbol, if (e.comment.isDefined) 1 else 0) + } + } + + pack.members.foreach(recur(_, true)) + Counters(publicEntities, privateEntities, protectedEntities, publicDocstrings, privateDocstrings, protectedDocstrings) + } +} diff --git a/doc-tool/src/dotty/tools/dottydoc/core/transform.scala b/doc-tool/src/dotty/tools/dottydoc/core/transform.scala new file mode 100644 index 000000000..e4b9ae6b6 --- /dev/null +++ b/doc-tool/src/dotty/tools/dottydoc/core/transform.scala @@ -0,0 +1,232 @@ +package dotty.tools +package dottydoc +package core + +import dotc.CompilationUnit +import dotc.core.Contexts.Context +import dotc.core.Comments.ContextDocstrings +import dotc.core.Phases.Phase +import model._ +import model.internal._ +import util.syntax._ +import util.traversing._ + +object transform { + /** + * The idea behind DocMiniTransformations is to fuse transformations to the + * doc AST, much like `MiniPhaseTransform` in dotty core - but in a much more + * simple implementation + * + * Usage + * ----- + * + * Create a `DocMiniPhase` which overrides the relevant method: + * + * ``` + * override def transformDef(implicit ctx: Context) = { + * case x if shouldTransform(x) => x.copy(newValue = ...) + * } + * ``` + * + * On each node in the AST, the appropriate method in `DocMiniPhase` will be + * called in the order that they are supplied in + * `DocMiniphaseTransformations`. + * + * There won't be a match-error as `transformX` is composed with an + * `identity` function. + * + * The transformations in `DocMiniTransformations` will apply transformations + * to all nodes - this means that you do _not_ need to transform children in + * `transformPackage`, because `transformX` will be called for the relevant + * children. If you want to add children to `Package` you need to do that in + * `transformPackage`, these additions will be persisted. + * + * Deleting nodes in the AST + * ------------------------- + * To delete a node in the AST, simply return `NonEntity` from transforming method + */ + trait DocMiniTransformations extends Phase { + def transformations: List[DocMiniPhase] + + override def runOn(units: List[CompilationUnit])(implicit ctx: Context): List[CompilationUnit] = { + for { + pack <- rootPackages(ctx.docbase.packages) + transformed = performPackageTransform(pack) + } yield ctx.docbase.packagesMutable(pack.name) = transformed + units + } + + 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) => + f(transf)(oldE) + } + + if (transformedEntity eq NonEntity) NonEntity + else createNew(transformedEntity) + } + + def traverse(ent: Entity): Entity = ent match { + case p: Package => transformEntity(p, _.packageTransformation) { p => + val newPackage = PackageImpl( + p.symbol, + p.annotations, + p.name, + p.members.map(traverse).filterNot(_ eq NonEntity), + p.path, + p.superTypes, + p.comment, + p.parent + ) + + // Update reference in context to newPackage + ctx.docbase.packagesMutable += (newPackage.path.mkString(".") -> newPackage) + + newPackage + } + case t: TypeAlias => transformEntity(t, _.typeAliasTransformation) { t => + TypeAliasImpl( + t.symbol, + t.annotations, + t.modifiers, + t.name, + t.path, + t.alias, + t.comment, + t.parent + ) + } + case c: Class => transformEntity(c, _.classTransformation) { cls => + ClassImpl( + cls.symbol, + cls.annotations, + cls.name, + cls.members.map(traverse).filterNot(_ eq NonEntity), + cls.modifiers, + cls.path, + cls.typeParams, + cls.constructors, + cls.superTypes, + cls.comment, + cls.companionPath, + cls.parent + ) + } + case cc: CaseClass => transformEntity(cc, _.caseClassTransformation) { cc => + CaseClassImpl( + cc.symbol, + cc.annotations, + cc.name, + cc.members.map(traverse).filterNot(_ eq NonEntity), + cc.modifiers, + cc.path, + cc.typeParams, + cc.constructors, + cc.superTypes, + cc.comment, + cc.companionPath, + cc.parent + ) + } + case trt: Trait => transformEntity(trt, _.traitTransformation) { trt => + TraitImpl( + trt.symbol, + trt.annotations, + trt.name, + trt.members.map(traverse).filterNot(_ eq NonEntity), + trt.modifiers, + trt.path, + trt.typeParams, + trt.traitParams, + trt.superTypes, + trt.comment, + trt.companionPath, + trt.parent + ) + } + case obj: Object => transformEntity(obj, _.objectTransformation) { obj => + ObjectImpl( + obj.symbol, + obj.annotations, + obj.name, + obj.members.map(traverse).filterNot(_ eq NonEntity), + obj.modifiers, + obj.path, + obj.superTypes, + obj.comment, + obj.companionPath, + obj.parent + ) + } + case df: Def => transformEntity(df, _.defTransformation) { df => + DefImpl( + df.symbol, + df.annotations, + df.name, + df.modifiers, + df.path, + df.returnValue, + df.typeParams, + df.paramLists, + df.comment, + df.implicitlyAddedFrom, + df.parent + ) + } + case vl: Val => transformEntity(vl, _.valTransformation) { vl => + ValImpl( + vl.symbol, + vl.annotations, + vl.name, + vl.modifiers, + vl.path, + vl.returnValue, + vl.kind, + vl.comment, + vl.implicitlyAddedFrom, + vl.parent + ) + } + } + + traverse(pack).asInstanceOf[Package] + } + + override def run(implicit ctx: Context): Unit = () + } + + object DocMiniTransformations { + private var previousPhase = 0 + def apply(miniPhases: DocMiniPhase*) = + new DocMiniTransformations { + val transformations = miniPhases.toList + val packages = Map.empty[String, Package] + + def phaseName = s"MiniTransformation${ previousPhase += 1 }" + } + } + + trait DocMiniPhase { phase => + private def identity[E]: PartialFunction[E, E] = { + case id: E @unchecked => id + } + + def transformPackage(implicit ctx: Context): PartialFunction[Package, Package] = identity + def transformTypeAlias(implicit ctx: Context): PartialFunction[TypeAlias, TypeAlias] = identity + def transformClass(implicit ctx: Context): PartialFunction[Class, Class] = identity + def transformCaseClass(implicit ctx: Context): PartialFunction[CaseClass, CaseClass] = identity + def transformTrait(implicit ctx: Context): PartialFunction[Trait, Trait] = identity + def transformObject(implicit ctx: Context): PartialFunction[Object, Object] = identity + def transformDef(implicit ctx: Context): PartialFunction[Def, Def] = identity + def transformVal(implicit ctx: Context): PartialFunction[Val, Val] = identity + + private[transform] def packageTransformation(p: Package)(implicit ctx: Context) = (transformPackage orElse identity)(p) + private[transform] def typeAliasTransformation(alias: TypeAlias)(implicit ctx: Context) = (transformTypeAlias orElse identity)(alias) + private[transform] def classTransformation(cls: Class)(implicit ctx: Context) = (transformClass orElse identity)(cls) + private[transform] def caseClassTransformation(cc: CaseClass)(implicit ctx: Context) = (transformCaseClass orElse identity)(cc) + private[transform] def traitTransformation(trt: Trait)(implicit ctx: Context) = (transformTrait orElse identity)(trt) + private[transform] def objectTransformation(obj: Object)(implicit ctx: Context) = (transformObject orElse identity)(obj) + private[transform] def defTransformation(df: Def)(implicit ctx: Context) = (transformDef orElse identity)(df) + private[transform] def valTransformation(vl: Val)(implicit ctx: Context) = (transformVal orElse identity)(vl) + } +} diff --git a/doc-tool/src/dotty/tools/dottydoc/util/traversing.scala b/doc-tool/src/dotty/tools/dottydoc/util/traversing.scala index 9c2e3bf54..956cb9291 100644 --- a/doc-tool/src/dotty/tools/dottydoc/util/traversing.scala +++ b/doc-tool/src/dotty/tools/dottydoc/util/traversing.scala @@ -24,7 +24,7 @@ object traversing { } - def rootPackages(pkgs: Map[String, Package]): List[String] = { + def rootPackages(pkgs: Map[String, Package]): List[Package] = { var currentDepth = Int.MaxValue var packs = List.empty[String] @@ -38,6 +38,6 @@ object traversing { key :: packs } else packs } - packs + packs.map(pkgs.apply) } } -- cgit v1.2.3