aboutsummaryrefslogtreecommitdiff
path: root/doc-tool
diff options
context:
space:
mode:
authorFelix Mulder <felix.mulder@gmail.com>2017-02-14 21:31:13 +0100
committerFelix Mulder <felix.mulder@gmail.com>2017-02-22 21:30:20 +0100
commit18c673073c29641cdd8386253ee34d7e4007b3b1 (patch)
tree8b00299367409c3133698594d95db0cc71578299 /doc-tool
parent859aca9616aaeebf918c642da4610669b3c00b2d (diff)
downloaddotty-18c673073c29641cdd8386253ee34d7e4007b3b1.tar.gz
dotty-18c673073c29641cdd8386253ee34d7e4007b3b1.tar.bz2
dotty-18c673073c29641cdd8386253ee34d7e4007b3b1.zip
Add some basic stats to ddoc
Diffstat (limited to 'doc-tool')
-rw-r--r--doc-tool/src/dotty/tools/dottydoc/DocCompiler.scala3
-rw-r--r--doc-tool/src/dotty/tools/dottydoc/DocDriver.scala5
-rw-r--r--doc-tool/src/dotty/tools/dottydoc/core/ContextDottydoc.scala86
-rw-r--r--doc-tool/src/dotty/tools/dottydoc/core/DocASTPhase.scala5
-rw-r--r--doc-tool/src/dotty/tools/dottydoc/core/DocstringPhase.scala1
-rw-r--r--doc-tool/src/dotty/tools/dottydoc/core/StatisticsPhase.scala156
-rw-r--r--doc-tool/src/dotty/tools/dottydoc/core/transform.scala (renamed from doc-tool/src/dotty/tools/dottydoc/core/MiniPhaseTransform.scala)15
-rw-r--r--doc-tool/src/dotty/tools/dottydoc/util/traversing.scala4
8 files changed, 259 insertions, 16 deletions
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/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/MiniPhaseTransform.scala b/doc-tool/src/dotty/tools/dottydoc/core/transform.scala
index 1f30e089d..e4b9ae6b6 100644
--- a/doc-tool/src/dotty/tools/dottydoc/core/MiniPhaseTransform.scala
+++ b/doc-tool/src/dotty/tools/dottydoc/core/transform.scala
@@ -45,15 +45,15 @@ object transform {
* -------------------------
* To delete a node in the AST, simply return `NonEntity` from transforming method
*/
- abstract class DocMiniTransformations(transformations: List[DocMiniPhase]) extends Phase {
+ trait DocMiniTransformations extends Phase {
+ def transformations: List[DocMiniPhase]
override def runOn(units: List[CompilationUnit])(implicit ctx: Context): List[CompilationUnit] = {
for {
- rootName <- rootPackages(ctx.docbase.packages)
- pack = ctx.docbase.packages(rootName)
+ pack <- rootPackages(ctx.docbase.packages)
transformed = performPackageTransform(pack)
- } yield ctx.docbase.packagesMutable(rootName) = transformed
- super.runOn(units)
+ } yield ctx.docbase.packagesMutable(pack.name) = transformed
+ units
}
private def performPackageTransform(pack: Package)(implicit ctx: Context): Package = {
@@ -197,8 +197,9 @@ object transform {
object DocMiniTransformations {
private var previousPhase = 0
- def apply(transformations: DocMiniPhase*) =
- new DocMiniTransformations(transformations.toList) {
+ def apply(miniPhases: DocMiniPhase*) =
+ new DocMiniTransformations {
+ val transformations = miniPhases.toList
val packages = Map.empty[String, Package]
def phaseName = s"MiniTransformation${ previousPhase += 1 }"
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)
}
}