Skip to content

[doc] Add support for usecases #1472

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 11 commits into from
4 changes: 3 additions & 1 deletion dottydoc/src/dotty/tools/dottydoc/DottyDoc.scala
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ class DocCompiler extends Compiler {
List(new DocFrontEnd),
List(new DocImplicitsPhase),
List(new DocASTPhase),
List(DocMiniTransformations(new LinkReturnTypes,
List(DocMiniTransformations(new UsecasePhase,
new DocstringPhase,
new LinkReturnTypes,
new LinkParamListTypes,
new LinkImplicitlyAddedTypes,
new LinkSuperTypes,
Expand Down
72 changes: 25 additions & 47 deletions dottydoc/src/dotty/tools/dottydoc/core/DocASTPhase.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ class DocASTPhase extends Phase {
import model._
import model.factories._
import model.internal._
import model.parsers.WikiParser
import model.comment.Comment
import dotty.tools.dotc.core.Flags
import dotty.tools.dotc.ast.tpd._
Expand All @@ -23,20 +22,8 @@ class DocASTPhase extends Phase {

def phaseName = "docphase"

private[this] val commentParser = new WikiParser

/** Saves the commentParser function for later evaluation, for when the AST has been filled */
def track(symbol: Symbol, ctx: Context, parent: Symbol = NoSymbol)(op: => Entity) = {
val entity = op

if (entity != NonEntity)
commentParser += (entity, symbol, parent, ctx)

entity
}

/** Build documentation hierarchy from existing tree */
def collect(tree: Tree, prev: List[String] = Nil)(implicit ctx: Context): Entity = track(tree.symbol, ctx) {
def collect(tree: Tree, prev: List[String] = Nil)(implicit ctx: Context): Entity = {
val implicitConversions = ctx.docbase.defs(tree.symbol)

def collectList(xs: List[Tree], ps: List[String]): List[Entity] =
Expand All @@ -58,28 +45,26 @@ class DocASTPhase extends Phase {
val defs = sym.info.bounds.hi.membersBasedOnFlags(Flags.Method, Flags.Synthetic | Flags.Private)
.filterNot(_.symbol.owner.name.show == "Any")
.map { meth =>
track(meth.symbol, ctx, tree.symbol) {
DefImpl(
meth.symbol.name.show,
Nil,
path(meth.symbol),
returnType(meth.info),
typeParams(meth.symbol),
paramLists(meth.info),
implicitlyAddedFrom = Some(returnType(meth.symbol.owner.info))
)
}
DefImpl(
meth.symbol,
meth.symbol.name.show,
Nil,
path(meth.symbol),
returnType(meth.info),
typeParams(meth.symbol),
paramLists(meth.info),
implicitlyAddedFrom = Some(returnType(meth.symbol.owner.info))
)
}.toList

val vals = sym.info.fields.filterNot(_.symbol.is(Flags.Private | Flags.Synthetic)).map { value =>
track(value.symbol, ctx, tree.symbol) {
ValImpl(
value.symbol.name.show,
Nil, path(value.symbol),
returnType(value.info),
implicitlyAddedFrom = Some(returnType(value.symbol.owner.info))
)
}
ValImpl(
value.symbol,
value.symbol.name.show,
Nil, path(value.symbol),
returnType(value.info),
implicitlyAddedFrom = Some(returnType(value.symbol.owner.info))
)
}

defs ++ vals
Expand All @@ -90,38 +75,38 @@ class DocASTPhase extends Phase {
/** package */
case pd @ PackageDef(pid, st) =>
val newPath = prev :+ pid.name.toString
addEntity(PackageImpl(newPath.mkString("."), collectEntityMembers(st, newPath), newPath))
addEntity(PackageImpl(pd.symbol, newPath.mkString("."), collectEntityMembers(st, newPath), newPath))

/** trait */
case t @ TypeDef(n, rhs) if t.symbol.is(Flags.Trait) =>
val name = n.decode.toString
val newPath = prev :+ name
//TODO: should not `collectMember` from `rhs` - instead: get from symbol, will get inherited members as well
TraitImpl(name, collectMembers(rhs), flags(t), newPath, typeParams(t.symbol), traitParameters(t.symbol), superTypes(t))
TraitImpl(t.symbol, name, collectMembers(rhs), flags(t), newPath, typeParams(t.symbol), traitParameters(t.symbol), superTypes(t))

/** objects, on the format "Object$" so drop the last letter */
case o @ TypeDef(n, rhs) if o.symbol.is(Flags.Module) =>
val name = n.decode.toString.dropRight(1)
//TODO: should not `collectMember` from `rhs` - instead: get from symbol, will get inherited members as well
ObjectImpl(name, collectMembers(rhs, prev :+ name), flags(o), prev :+ (name + "$"), superTypes(o))
ObjectImpl(o.symbol, name, collectMembers(rhs, prev :+ name), flags(o), prev :+ (name + "$"), superTypes(o))

/** class / case class */
case c @ TypeDef(n, rhs) if c.symbol.isClass =>
val name = n.decode.toString
val newPath = prev :+ name
//TODO: should not `collectMember` from `rhs` - instead: get from symbol, will get inherited members as well
(name, collectMembers(rhs), flags(c), newPath, typeParams(c.symbol), constructors(c.symbol), superTypes(c), None) match {
(c.symbol, name, collectMembers(rhs), flags(c), newPath, typeParams(c.symbol), constructors(c.symbol), superTypes(c), None) match {
case x if c.symbol.is(Flags.CaseClass) => CaseClassImpl.tupled(x)
case x => ClassImpl.tupled(x)
}

/** def */
case d: DefDef =>
DefImpl(d.name.decode.toString, flags(d), path(d.symbol), returnType(d.tpt.tpe), typeParams(d.symbol), paramLists(d.symbol.info))
DefImpl(d.symbol, d.name.decode.toString, flags(d), path(d.symbol), returnType(d.tpt.tpe), typeParams(d.symbol), paramLists(d.symbol.info))

/** val */
case v: ValDef if !v.symbol.is(Flags.ModuleVal) =>
ValImpl(v.name.decode.toString, flags(v), path(v.symbol), returnType(v.tpt.tpe))
ValImpl(v.symbol, v.name.decode.toString, flags(v), path(v.symbol), returnType(v.tpt.tpe))

case x => {
//dottydoc.println(s"Found unwanted entity: $x (${x.pos},\n${x.show}")
Expand Down Expand Up @@ -175,14 +160,7 @@ class DocASTPhase extends Phase {
child <- parent.children
} setParent(child, to = parent)

// (3) Create documentation template from docstrings, with internal links
println("Generating documentation, this might take a while...")
commentParser.parse(packages)

// (4) Clear caches
commentParser.clear()

// (5) Update Doc AST in ctx.base
// (3) Update Doc AST in ctx.base
for (kv <- packages) ctx.docbase.packages += kv

// Return super's result
Expand Down
46 changes: 46 additions & 0 deletions dottydoc/src/dotty/tools/dottydoc/core/DocstringPhase.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package dotty.tools
package dottydoc
package core

import dotc.core.Contexts.Context
import transform.DocMiniPhase
import model._
import model.internal._
import model.comment._
import BodyParsers._

class DocstringPhase extends DocMiniPhase with CommentParser with CommentCleaner {
private def parsedComment[E <: Entity](ent: E)(implicit ctx: Context): Option[Comment] =
ctx.docbase.docstring(ent.symbol).map { cmt =>
parse(ent, ctx.docbase.packages[Package].toMap, clean(cmt.raw), cmt.raw, cmt.pos)
.toComment(_.toHtml(ent))
}

override def transformPackage(implicit ctx: Context) = { case ent: PackageImpl =>
ent.copy(comment = parsedComment(ent))
}

override def transformClass(implicit ctx: Context) = { case ent: ClassImpl =>
ent.copy(comment = parsedComment(ent))
}

override def transformCaseClass(implicit ctx: Context) = { case ent: CaseClassImpl =>
ent.copy(comment = parsedComment(ent))
}

override def transformTrait(implicit ctx: Context) = { case ent: TraitImpl =>
ent.copy(comment = parsedComment(ent))
}

override def transformObject(implicit ctx: Context) = { case ent: ObjectImpl =>
ent.copy(comment = parsedComment(ent))
}

override def transformDef(implicit ctx: Context) = { case ent: DefImpl =>
ent.copy(comment = parsedComment(ent))
}

override def transformVal(implicit ctx: Context) = { case ent: ValImpl =>
ent.copy(comment = parsedComment(ent))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ object transform {
def traverse(ent: Entity): Entity = ent match {
case p: Package => transformEntity(p, _.packageTransformation) { p =>
val newPackage = PackageImpl(
p.symbol,
p.name,
p.members.map(traverse),
p.path,
Expand All @@ -90,6 +91,7 @@ object transform {
}
case c: Class => transformEntity(c, _.classTransformation) { cls =>
ClassImpl(
cls.symbol,
cls.name,
cls.members.map(traverse),
cls.modifiers,
Expand All @@ -102,6 +104,7 @@ object transform {
}
case cc: CaseClass => transformEntity(cc, _.caseClassTransformation) { cc =>
CaseClassImpl(
cc.symbol,
cc.name,
cc.members.map(traverse),
cc.modifiers,
Expand All @@ -114,6 +117,7 @@ object transform {
}
case trt: Trait => transformEntity(trt, _.traitTransformation) { trt =>
TraitImpl(
trt.symbol,
trt.name,
trt.members.map(traverse),
trt.modifiers,
Expand All @@ -126,6 +130,7 @@ object transform {
}
case obj: Object => transformEntity(obj, _.objectTransformation) { obj =>
ObjectImpl(
obj.symbol,
obj.name,
obj.members.map(traverse),
obj.modifiers,
Expand All @@ -136,6 +141,7 @@ object transform {
}
case df: Def => transformEntity(df, _.defTransformation) { df =>
DefImpl(
df.symbol,
df.name,
df.modifiers,
df.path,
Expand All @@ -148,6 +154,7 @@ object transform {
}
case vl: Val => transformEntity(vl, _.valTransformation) { vl =>
ValImpl(
vl.symbol,
vl.name,
vl.modifiers,
vl.path,
Expand Down
30 changes: 30 additions & 0 deletions dottydoc/src/dotty/tools/dottydoc/core/UsecasePhase.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package dotty.tools
package dottydoc
package core

import dotc.core.Contexts.Context
import dotc.ast.tpd

import transform.DocMiniPhase
import model.internal._
import model.factories._
import dotty.tools.dotc.core.Symbols.Symbol

class UsecasePhase extends DocMiniPhase {
private def defdefToDef(d: tpd.DefDef, sym: Symbol)(implicit ctx: Context) = {
val name = d.name.show.split("\\$").head // UseCase defs get $pos appended to their names
DefImpl(
sym,
name,
flags(d),
path(d.symbol).init :+ name,
returnType(d.tpt.tpe),
typeParams(d.symbol),
paramLists(d.symbol.info)
)
}

override def transformDef(implicit ctx: Context) = { case df: DefImpl =>
ctx.docbase.docstring(df.symbol).flatMap(_.usecases.headOption.map(_.tpdCode)).map(defdefToDef(_, df.symbol)).getOrElse(df)
}
}
Loading