aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/dotty/tools/dotc/parsing/Parsers.scala34
-rw-r--r--src/dotty/tools/dotc/parsing/Scanners.scala29
-rw-r--r--test/test/DottyDocTests.scala48
3 files changed, 85 insertions, 26 deletions
diff --git a/src/dotty/tools/dotc/parsing/Parsers.scala b/src/dotty/tools/dotc/parsing/Parsers.scala
index ad50bf476..3aace28cf 100644
--- a/src/dotty/tools/dotc/parsing/Parsers.scala
+++ b/src/dotty/tools/dotc/parsing/Parsers.scala
@@ -1888,28 +1888,30 @@ object Parsers {
/** TmplDef ::= ([`case'] `class' | `trait') ClassDef
* | [`case'] `object' ObjectDef
*/
- def tmplDef(start: Int, mods: Modifiers): Tree = in.token match {
- case TRAIT =>
- classDef(posMods(start, addFlag(mods, Trait)))
- case CLASS =>
- classDef(posMods(start, mods))
- case CASECLASS =>
- classDef(posMods(start, mods | Case))
- case OBJECT =>
- objectDef(posMods(start, mods | Module))
- case CASEOBJECT =>
- objectDef(posMods(start, mods | Case | Module))
- case _ =>
- syntaxErrorOrIncomplete("expected start of definition")
- EmptyTree
+ def tmplDef(start: Int, mods: Modifiers): Tree = {
+ val docstring = in.getDocString()
+ in.token match {
+ case TRAIT =>
+ classDef(posMods(start, addFlag(mods, Trait)), docstring)
+ case CLASS =>
+ classDef(posMods(start, mods), docstring)
+ case CASECLASS =>
+ classDef(posMods(start, mods | Case), docstring)
+ case OBJECT =>
+ objectDef(posMods(start, mods | Module))
+ case CASEOBJECT =>
+ objectDef(posMods(start, mods | Case | Module))
+ case _ =>
+ syntaxErrorOrIncomplete("expected start of definition")
+ EmptyTree
+ }
}
/** ClassDef ::= Id [ClsTypeParamClause]
* [ConstrMods] ClsParamClauses TemplateOpt
*/
- def classDef(mods: Modifiers): TypeDef = atPos(tokenRange) {
+ def classDef(mods: Modifiers, docstring: Option[String]): TypeDef = atPos(tokenRange) {
val name = ident().toTypeName
- val docstring = in.getDocString()
val constr = atPos(in.offset) {
val tparams = typeParamClauseOpt(ParamOwner.Class)
val cmods = constrModsOpt()
diff --git a/src/dotty/tools/dotc/parsing/Scanners.scala b/src/dotty/tools/dotc/parsing/Scanners.scala
index 438c54398..60042e5a6 100644
--- a/src/dotty/tools/dotc/parsing/Scanners.scala
+++ b/src/dotty/tools/dotc/parsing/Scanners.scala
@@ -185,12 +185,23 @@ object Scanners {
/** The currently closest docstring, replaced every time a new docstring is
* encountered
*/
- val closestDocString: mutable.Queue[Comment] = mutable.Queue.empty
+ var closestDocString: List[mutable.Queue[Comment]] = mutable.Queue.empty[Comment] :: Nil
+
+ /** Adds level of nesting to docstrings */
+ def enterBlock(): Unit =
+ closestDocString = mutable.Queue.empty[Comment] :: closestDocString
+
+ /** Removes level of nesting for docstrings */
+ def exitBlock(): Unit = closestDocString = closestDocString match {
+ case x :: Nil => mutable.Queue.empty[Comment] :: Nil
+ case _ => closestDocString.tail
+ }
/** Returns `closestDocString`'s raw string and sets it to `None` */
- def getDocString(): Option[String] =
- if (closestDocString.isEmpty) None
- else Some(closestDocString.dequeue.chrs)
+ def getDocString(): Option[String] = closestDocString match {
+ case x :: _ if !x.isEmpty => Some(x.dequeue.chrs)
+ case _ => None
+ }
/** A buffer for comments */
val commentBuf = new StringBuilder
@@ -497,13 +508,13 @@ object Scanners {
case ',' =>
nextChar(); token = COMMA
case '(' =>
- nextChar(); token = LPAREN
+ enterBlock(); nextChar(); token = LPAREN
case '{' =>
- nextChar(); token = LBRACE
+ enterBlock(); nextChar(); token = LBRACE
case ')' =>
- nextChar(); token = RPAREN
+ exitBlock(); nextChar(); token = RPAREN
case '}' =>
- nextChar(); token = RBRACE
+ exitBlock(); nextChar(); token = RBRACE
case '[' =>
nextChar(); token = LBRACKET
case ']' =>
@@ -569,7 +580,7 @@ object Scanners {
val comment = Comment(pos, flushBuf(commentBuf))
if (comment.isDocComment)
- closestDocString.enqueue(comment)
+ closestDocString.head.enqueue(comment)
if (keepComments)
revComments = comment :: revComments
diff --git a/test/test/DottyDocTests.scala b/test/test/DottyDocTests.scala
index df53c2ae9..af3336cb7 100644
--- a/test/test/DottyDocTests.scala
+++ b/test/test/DottyDocTests.scala
@@ -60,7 +60,9 @@ object DottyDocTests extends DottyTest {
SingleCaseClassWithoutPackage,
SingleTraitWihoutPackage,
MultipleTraitsWithoutPackage,
- MultipleMixedEntitiesWithPackage
+ MultipleMixedEntitiesWithPackage,
+ NestedClass,
+ NestedClassThenOuter
)
def main(args: Array[String]): Unit = {
@@ -185,3 +187,47 @@ case object MultipleMixedEntitiesWithPackage extends DottyDocTest {
}
}
}
+
+case object NestedClass extends DottyDocTest {
+ override val source =
+ """
+ |/** Outer docstring */
+ |class Outer {
+ | /** Inner docstring */
+ | class Inner(val x: Int)
+ |}
+ """.stripMargin
+
+ override def assertion = {
+ case PackageDef(_, Seq(outer @ TypeDef(_, tpl @ Template(_,_,_,_)))) =>
+ checkDocString(outer.rawComment, "/** Outer docstring */")
+ tpl.body match {
+ case (inner @ TypeDef(_,_)) :: _ => checkDocString(inner.rawComment, "/** Inner docstring */")
+ case _ => assert(false, "Couldn't find inner class")
+ }
+ }
+}
+
+case object NestedClassThenOuter extends DottyDocTest {
+ override val source =
+ """
+ |/** Outer1 docstring */
+ |class Outer1 {
+ | /** Inner docstring */
+ | class Inner(val x: Int)
+ |}
+ |
+ |/** Outer2 docstring */
+ |class Outer2
+ """.stripMargin
+
+ override def assertion = {
+ case PackageDef(_, Seq(o1 @ TypeDef(_, tpl @ Template(_,_,_,_)), o2 @ TypeDef(_,_))) =>
+ checkDocString(o1.rawComment, "/** Outer1 docstring */")
+ checkDocString(o2.rawComment, "/** Outer2 docstring */")
+ tpl.body match {
+ case (inner @ TypeDef(_,_)) :: _ => checkDocString(inner.rawComment, "/** Inner docstring */")
+ case _ => assert(false, "Couldn't find inner class")
+ }
+ }
+}