Skip to content

Commit 9253616

Browse files
committed
Separate ContextDocstrings from Context and make it pluggable
1 parent 208232a commit 9253616

File tree

13 files changed

+143
-109
lines changed

13 files changed

+143
-109
lines changed

dottydoc/src/dotty/tools/dottydoc/DottyDoc.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import core.transform._
77
import dotc.config.CompilerCommand
88
import dotc.config.Printers.dottydoc
99
import dotc.core.Contexts._
10+
import dotc.core.Comments.ContextDoc
1011
import dotc.core.Phases.Phase
1112
import dotc.typer.FrontEnd
1213
import dotc.{ CompilationUnit, Compiler, Driver, Run }
@@ -57,7 +58,7 @@ abstract class DocDriver extends Driver {
5758

5859
ctx.setSettings(summary.sstate)
5960
ctx.setSetting(ctx.settings.YkeepComments, true)
60-
ctx.setProperty(DocContext, new DocBase)
61+
ctx.setProperty(ContextDoc, new ContextDottydoc)
6162

6263
val fileNames = CompilerCommand.checkUsage(summary, sourcesRequired)(ctx)
6364
(fileNames, ctx)
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+
package core
4+
5+
import dotc.core.Symbols.Symbol
6+
import dotc.core.Comments.ContextDocstrings
7+
import model.Package
8+
9+
class ContextDottydoc extends ContextDocstrings {
10+
import scala.collection.mutable
11+
12+
private[this] val _packages: mutable.Map[String, Package] = mutable.Map.empty
13+
def packages: Map[String, Package] = _packages.toMap
14+
def packagesMutable: mutable.Map[String, Package] = _packages
15+
16+
/** Should perhaps factorize this into caches that get flushed */
17+
private var _defs: Map[Symbol, Set[Symbol]] = Map.empty
18+
def defs(sym: Symbol): Set[Symbol] = _defs.get(sym).getOrElse(Set.empty)
19+
20+
def addDef(s: Symbol, d: Symbol): Unit = _defs = (_defs + {
21+
s -> _defs.get(s).map(xs => xs + d).getOrElse(Set(d))
22+
})
23+
}

dottydoc/src/dotty/tools/dottydoc/core/DocASTPhase.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ package core
66
import dotc.ast.Trees._
77
import dotc.CompilationUnit
88
import dotc.config.Printers.dottydoc
9-
import dotc.core.Contexts.{ Context, DocBase }
9+
import dotc.core.Contexts.Context
10+
import dotc.core.Comments.ContextDocstrings
1011
import dotc.core.Phases.Phase
1112
import dotc.core.Symbols.{ Symbol, NoSymbol }
1213

dottydoc/src/dotty/tools/dottydoc/core/MiniPhaseTransform.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ package dottydoc
33
package core
44

55
import dotc.CompilationUnit
6-
import dotc.core.Contexts.{ Context, DocBase }
6+
import dotc.core.Contexts.Context
7+
import dotc.core.Comments.ContextDocstrings
78
import dotc.core.Phases.Phase
89
import model._
910
import model.internal._

dottydoc/src/dotty/tools/dottydoc/util/syntax.scala

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,15 @@ package dotty.tools
22
package dottydoc
33
package util
44

5-
import dotc.core.Contexts.{ Context, DocBase }
5+
import dotc.core.Contexts.Context
6+
import dotc.core.Comments._
67
import model.Package
8+
import core.ContextDottydoc
79

810
object syntax {
9-
implicit class RichDocContext(val ctx: Context) extends AnyVal {
10-
def docbase: DocBase = ctx.getDocbase getOrElse {
11+
implicit class ContextWithContextDottydoc(val ctx: Context) extends AnyVal {
12+
def docbase: ContextDottydoc = ctx.docCtx.getOrElse {
1113
throw new IllegalStateException("DocBase must be set before running dottydoc phases")
12-
}
13-
}
14-
15-
implicit class RichDocBase(val db: DocBase) {
16-
def packages: Map[String, Package] = db.packagesAs[Package].toMap
17-
18-
def packagesMutable: collection.mutable.Map[String, Package] =
19-
db.packagesAs[Package]
14+
}.asInstanceOf[ContextDottydoc]
2015
}
2116
}

dottydoc/test/BaseTest.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
package dotty.tools
22
package dottydoc
33

4-
import dotc.core.Contexts
5-
import Contexts.{ Context, ContextBase, FreshContext, DocContext, DocBase }
4+
import dotc.core.Contexts.{ Context, ContextBase, FreshContext }
5+
import dotc.core.Comments.{ ContextDoc, ContextDocstrings }
66
import dotc.util.SourceFile
77
import dotc.core.Phases.Phase
88
import dotc.typer.FrontEnd
9-
import dottydoc.core.DocASTPhase
9+
import dottydoc.core.{ DocASTPhase, ContextDottydoc }
1010
import model.Package
1111
import dotty.tools.dottydoc.util.syntax._
1212

@@ -20,7 +20,7 @@ trait DottyTest {
2020
ctx.setSetting(ctx.settings.language, List("Scala2"))
2121
ctx.setSetting(ctx.settings.YnoInline, true)
2222
ctx.setSetting(ctx.settings.YkeepComments, true)
23-
ctx.setProperty(DocContext, new DocBase)
23+
ctx.setProperty(ContextDoc, new ContextDottydoc)
2424
base.initialize()(ctx)
2525
ctx
2626
}

src/dotty/tools/dotc/core/Comments.scala

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,40 @@ package dotty.tools
22
package dotc
33
package core
44

5-
import dotc.ast.{ untpd, tpd }
6-
import Decorators._
7-
import Symbols._
8-
import Contexts.Context
9-
import Flags.EmptyFlags
10-
import dotc.util.SourceFile
11-
import dotc.util.Positions._
12-
import dotc.util.CommentParsing._
13-
import dotc.parsing.Parsers.Parser
5+
import ast.{ untpd, tpd }
6+
import Decorators._, Symbols._, Contexts._, Flags.EmptyFlags
7+
import util.SourceFile
8+
import util.Positions._
9+
import util.CommentParsing._
10+
import util.Property.Key
11+
import parsing.Parsers.Parser
1412

1513
object Comments {
14+
val ContextDoc = new Key[ContextDocstrings]
15+
16+
/** Decorator for getting docbase out of context */
17+
implicit class CommentsContext(val ctx: Context) extends AnyVal {
18+
def docCtx: Option[ContextDocstrings] = ctx.property(ContextDoc)
19+
}
20+
21+
/** Context for Docstrings, contains basic functionality for getting
22+
* docstrings via `Symbol` and expanding templates
23+
*/
24+
class ContextDocstrings {
25+
import scala.collection.mutable
26+
27+
private[this] val _docstrings: mutable.Map[Symbol, Comment] =
28+
mutable.Map.empty
29+
30+
val templateExpander = new CommentExpander
31+
32+
def docstrings: Map[Symbol, Comment] = _docstrings.toMap
33+
34+
def docstring(sym: Symbol): Option[Comment] = _docstrings.get(sym)
35+
36+
def addDocstring(sym: Symbol, doc: Option[Comment]): Unit =
37+
doc.map(d => _docstrings += (sym -> d))
38+
}
1639

1740
abstract case class Comment(pos: Position, raw: String)(implicit ctx: Context) { self =>
1841
def isExpanded: Boolean
@@ -155,7 +178,7 @@ object Comments {
155178
*/
156179
def cookedDocComment(sym: Symbol, docStr: String = "")(implicit ctx: Context): String = cookedDocComments.getOrElseUpdate(sym, {
157180
var ownComment =
158-
if (docStr.length == 0) ctx.getDocbase.flatMap(_.docstring(sym).map(c => template(c.raw))).getOrElse("")
181+
if (docStr.length == 0) ctx.docCtx.flatMap(_.docstring(sym).map(c => template(c.raw))).getOrElse("")
159182
else template(docStr)
160183
ownComment = replaceInheritDocToInheritdoc(ownComment)
161184

@@ -365,7 +388,7 @@ object Comments {
365388
def defineVariables(sym: Symbol)(implicit ctx: Context) = {
366389
val Trim = "(?s)^[\\s&&[^\n\r]]*(.*?)\\s*$".r
367390

368-
val raw = ctx.getDocbase.flatMap(_.docstring(sym).map(_.raw)).getOrElse("")
391+
val raw = ctx.docCtx.flatMap(_.docstring(sym).map(_.raw)).getOrElse("")
369392
defs(sym) ++= defines(raw).map {
370393
str => {
371394
val start = skipWhitespace(str, "@define".length)
@@ -406,7 +429,7 @@ object Comments {
406429
* the position of the doc comment of the overridden version is returned instead.
407430
*/
408431
def docCommentPos(sym: Symbol)(implicit ctx: Context): Position =
409-
ctx.getDocbase.flatMap(_.docstring(sym).map(_.pos)).getOrElse(NoPosition)
432+
ctx.docCtx.flatMap(_.docstring(sym).map(_.pos)).getOrElse(NoPosition)
410433

411434
/** A version which doesn't consider self types, as a temporary measure:
412435
* an infinite loop has broken out between superComment and cookedDocComment

src/dotty/tools/dotc/core/Contexts.scala

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,6 @@ object Contexts {
6969
/** The context base at the root */
7070
val base: ContextBase
7171

72-
/** Documentation base */
73-
def getDocbase = property(DocContext)
74-
7572
/** All outer contexts, ending in `base.initialCtx` and then `NoContext` */
7673
def outersIterator = new Iterator[Context] {
7774
var current = thiscontext
@@ -578,37 +575,6 @@ object Contexts {
578575
}
579576
}
580577

581-
val DocContext = new Key[DocBase]
582-
class DocBase {
583-
private[this] val _docstrings: mutable.Map[Symbol, Comment] =
584-
mutable.Map.empty
585-
586-
val templateExpander = new CommentExpander
587-
588-
def docstrings: Map[Symbol, Comment] = _docstrings.toMap
589-
590-
def docstring(sym: Symbol): Option[Comment] = _docstrings.get(sym)
591-
592-
def addDocstring(sym: Symbol, doc: Option[Comment]): Unit =
593-
doc.map(d => _docstrings += (sym -> d))
594-
595-
/*
596-
* Dottydoc places instances of `Package` in this map - but we do not want
597-
* to depend on `dottydoc` for the compiler, as such this is defined as a
598-
* map of `String -> AnyRef`
599-
*/
600-
private[this] val _packages: mutable.Map[String, AnyRef] = mutable.Map.empty
601-
def packagesAs[A]: mutable.Map[String, A] = _packages.asInstanceOf[mutable.Map[String, A]]
602-
603-
/** Should perhaps factorize this into caches that get flushed */
604-
private var _defs: Map[Symbol, Set[Symbol]] = Map.empty
605-
def defs(sym: Symbol): Set[Symbol] = _defs.get(sym).getOrElse(Set.empty)
606-
607-
def addDef(s: Symbol, d: Symbol): Unit = _defs = (_defs + {
608-
s -> _defs.get(s).map(xs => xs + d).getOrElse(Set(d))
609-
})
610-
}
611-
612578
/** The essential mutable state of a context base, collected into a common class */
613579
class ContextState {
614580
// Symbols state

src/dotty/tools/dotc/core/SymDenotations.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package dotc
33
package core
44

55
import Periods._, Contexts._, Symbols._, Denotations._, Names._, NameOps._, Annotations._
6-
import Types._, Flags._, Decorators._, DenotTransformers._, StdNames._, Scopes._
6+
import Types._, Flags._, Decorators._, DenotTransformers._, StdNames._, Scopes._, Comments._
77
import NameOps._
88
import Scopes.Scope
99
import collection.mutable
@@ -1541,7 +1541,7 @@ object SymDenotations {
15411541

15421542
/** Enter a symbol in given `scope` without potentially replacing the old copy. */
15431543
def enterNoReplace(sym: Symbol, scope: MutableScope)(implicit ctx: Context): Unit = {
1544-
def isUsecase = ctx.property(DocContext).isDefined && sym.name.show.takeRight(4) == "$doc"
1544+
def isUsecase = ctx.docCtx.isDefined && sym.name.show.takeRight(4) == "$doc"
15451545
require(
15461546
(sym.denot.flagsUNSAFE is Private) ||
15471547
!(this is Frozen) ||
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package dotty.tools
2+
package dotc
3+
package typer
4+
5+
import core._
6+
import Contexts._, Symbols._, Decorators._, Comments._
7+
import util.Positions._
8+
import ast.tpd
9+
10+
trait Docstrings { self: Typer =>
11+
12+
/** The Docstrings typer will handle the expansion of `@define` and
13+
* `@inheritdoc` if there is a `DocContext` present as a property in the
14+
* supplied `ctx`.
15+
*
16+
* It will also type any `@usecase` available in function definitions.
17+
*/
18+
def cookComments(syms: List[Symbol], owner: Symbol)(implicit ctx: Context): Unit =
19+
ctx.docCtx.foreach { docbase =>
20+
val relevantSyms = syms.filter(docbase.docstring(_).isDefined)
21+
relevantSyms.foreach { sym =>
22+
expandParentDocs(sym)
23+
val usecases = docbase.docstring(sym).map(_.usecases).getOrElse(Nil)
24+
25+
usecases.foreach { usecase =>
26+
enterSymbol(createSymbol(usecase.untpdCode))
27+
28+
typedStats(usecase.untpdCode :: Nil, owner) match {
29+
case List(df: tpd.DefDef) => usecase.tpdCode = df
30+
case _ => ctx.error("`@usecase` was not a valid definition", usecase.codePos)
31+
}
32+
}
33+
}
34+
}
35+
36+
private def expandParentDocs(sym: Symbol)(implicit ctx: Context): Unit =
37+
ctx.docCtx.foreach { docCtx =>
38+
docCtx.docstring(sym).foreach { cmt =>
39+
def expandDoc(owner: Symbol): Unit = if (!cmt.isExpanded) {
40+
val tplExp = docCtx.templateExpander
41+
tplExp.defineVariables(sym)
42+
43+
val newCmt = cmt
44+
.expand(tplExp.expandedDocComment(sym, owner, _))
45+
.withUsecases
46+
47+
docCtx.addDocstring(sym, Some(newCmt))
48+
}
49+
50+
if (sym ne NoSymbol) {
51+
expandParentDocs(sym.owner)
52+
expandDoc(sym.owner)
53+
}
54+
}
55+
}
56+
}

src/dotty/tools/dotc/typer/Namer.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -457,7 +457,7 @@ class Namer { typer: Typer =>
457457

458458
def setDocstring(sym: Symbol, tree: Tree)(implicit ctx: Context) = tree match {
459459
case t: MemberDef if t.rawComment.isDefined =>
460-
ctx.getDocbase.foreach(_.addDocstring(sym, t.rawComment))
460+
ctx.docCtx.foreach(_.addDocstring(sym, t.rawComment))
461461
case _ => ()
462462
}
463463

src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 3 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ object Typer {
5858
assert(tree.pos.exists, s"position not set for $tree # ${tree.uniqueId}")
5959
}
6060

61-
class Typer extends Namer with TypeAssigner with Applications with Implicits with Dynamic with Checking {
61+
class Typer extends Namer with TypeAssigner with Applications with Implicits with Dynamic with Checking with Docstrings {
6262

6363
import Typer._
6464
import tpd.{cpy => _, _}
@@ -1247,8 +1247,8 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
12471247
val dummy = localDummy(cls, impl)
12481248
val body1 = typedStats(impl.body, dummy)(inClassContext(self1.symbol))
12491249

1250-
if (ctx.property(DocContext).isDefined)
1251-
typedUsecases(body1.map(_.symbol), self1.symbol)(localContext(cdef, cls).setNewScope)
1250+
// Expand comments and type usecases
1251+
cookComments(body1.map(_.symbol), self1.symbol)(localContext(cdef, cls).setNewScope)
12521252

12531253
checkNoDoubleDefs(cls)
12541254
val impl1 = cpy.Template(impl)(constr1, parents1, self1, body1)
@@ -1538,45 +1538,6 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
15381538
tpd.cpy.DefDef(mdef)(rhs = Inliner.bodyToInline(mdef.symbol)) ::
15391539
Inliner.removeInlineAccessors(mdef.symbol)
15401540

1541-
private def typedUsecases(syms: List[Symbol], owner: Symbol)(implicit ctx: Context): Unit =
1542-
ctx.getDocbase.foreach { docbase =>
1543-
val relevantSyms = syms.filter(docbase.docstring(_).isDefined)
1544-
relevantSyms.foreach { sym =>
1545-
expandParentDocs(sym)
1546-
val usecases = docbase.docstring(sym).map(_.usecases).getOrElse(Nil)
1547-
1548-
usecases.foreach { usecase =>
1549-
enterSymbol(createSymbol(usecase.untpdCode))
1550-
1551-
typedStats(usecase.untpdCode :: Nil, owner) match {
1552-
case List(df: tpd.DefDef) => usecase.tpdCode = df
1553-
case _ => ctx.error("`@usecase` was not a valid definition", usecase.codePos)
1554-
}
1555-
}
1556-
}
1557-
}
1558-
1559-
private def expandParentDocs(sym: Symbol)(implicit ctx: Context): Unit =
1560-
ctx.getDocbase.foreach { docbase =>
1561-
docbase.docstring(sym).foreach { cmt =>
1562-
def expandDoc(owner: Symbol): Unit = if (!cmt.isExpanded) {
1563-
val tplExp = docbase.templateExpander
1564-
tplExp.defineVariables(sym)
1565-
1566-
val newCmt = cmt
1567-
.expand(tplExp.expandedDocComment(sym, owner, _))
1568-
.withUsecases
1569-
1570-
docbase.addDocstring(sym, Some(newCmt))
1571-
}
1572-
1573-
if (sym ne NoSymbol) {
1574-
expandParentDocs(sym.owner)
1575-
expandDoc(sym.owner)
1576-
}
1577-
}
1578-
}
1579-
15801541
def typedExpr(tree: untpd.Tree, pt: Type = WildcardType)(implicit ctx: Context): Tree =
15811542
typed(tree, pt)(ctx retractMode Mode.PatternOrType)
15821543
def typedType(tree: untpd.Tree, pt: Type = WildcardType)(implicit ctx: Context): Tree = // todo: retract mode between Type and Pattern?

0 commit comments

Comments
 (0)