Skip to content

Commit 4f7c4af

Browse files
committed
Add docstring support for types, vals, vars and defs
1 parent ef57eae commit 4f7c4af

File tree

2 files changed

+150
-15
lines changed

2 files changed

+150
-15
lines changed

src/dotty/tools/dotc/parsing/Parsers.scala

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1750,13 +1750,13 @@ object Parsers {
17501750
*/
17511751
def defOrDcl(start: Int, mods: Modifiers): Tree = in.token match {
17521752
case VAL =>
1753-
patDefOrDcl(posMods(start, mods))
1753+
patDefOrDcl(posMods(start, mods), in.getDocString(start))
17541754
case VAR =>
1755-
patDefOrDcl(posMods(start, addFlag(mods, Mutable)))
1755+
patDefOrDcl(posMods(start, addFlag(mods, Mutable)), in.getDocString(start))
17561756
case DEF =>
1757-
defDefOrDcl(posMods(start, mods))
1757+
defDefOrDcl(posMods(start, mods), in.getDocString(start))
17581758
case TYPE =>
1759-
typeDefOrDcl(posMods(start, mods))
1759+
typeDefOrDcl(posMods(start, mods), in.getDocString(start))
17601760
case _ =>
17611761
tmplDef(start, mods)
17621762
}
@@ -1766,7 +1766,7 @@ object Parsers {
17661766
* ValDcl ::= Id {`,' Id} `:' Type
17671767
* VarDcl ::= Id {`,' Id} `:' Type
17681768
*/
1769-
def patDefOrDcl(mods: Modifiers): Tree = {
1769+
def patDefOrDcl(mods: Modifiers, docstring: Option[String] = None): Tree = {
17701770
val lhs = commaSeparated(pattern2)
17711771
val tpt = typedOpt()
17721772
val rhs =
@@ -1780,8 +1780,10 @@ object Parsers {
17801780
}
17811781
} else EmptyTree
17821782
lhs match {
1783-
case (id @ Ident(name: TermName)) :: Nil => cpy.ValDef(id)(name, tpt, rhs).withMods(mods)
1784-
case _ => PatDef(mods, lhs, tpt, rhs)
1783+
case (id @ Ident(name: TermName)) :: Nil =>
1784+
cpy.ValDef(id)(name, tpt, rhs).withMods(mods).withComment(docstring)
1785+
case _ =>
1786+
PatDef(mods, lhs, tpt, rhs)
17851787
}
17861788
}
17871789

@@ -1790,7 +1792,7 @@ object Parsers {
17901792
* DefDcl ::= DefSig `:' Type
17911793
* DefSig ::= id [DefTypeParamClause] ParamClauses
17921794
*/
1793-
def defDefOrDcl(mods: Modifiers): Tree = atPos(tokenRange) {
1795+
def defDefOrDcl(mods: Modifiers, docstring: Option[String] = None): Tree = atPos(tokenRange) {
17941796
def scala2ProcedureSyntax(resultTypeStr: String) = {
17951797
val toInsert =
17961798
if (in.token == LBRACE) s"$resultTypeStr ="
@@ -1831,7 +1833,7 @@ object Parsers {
18311833
accept(EQUALS)
18321834
expr()
18331835
}
1834-
DefDef(name, tparams, vparamss, tpt, rhs).withMods(mods1)
1836+
DefDef(name, tparams, vparamss, tpt, rhs).withMods(mods1).withComment(docstring)
18351837
}
18361838
}
18371839

@@ -1865,15 +1867,15 @@ object Parsers {
18651867
/** TypeDef ::= type Id [TypeParamClause] `=' Type
18661868
* TypeDcl ::= type Id [TypeParamClause] TypeBounds
18671869
*/
1868-
def typeDefOrDcl(mods: Modifiers): Tree = {
1870+
def typeDefOrDcl(mods: Modifiers, docstring: Option[String] = None): Tree = {
18691871
newLinesOpt()
18701872
atPos(tokenRange) {
18711873
val name = ident().toTypeName
18721874
val tparams = typeParamClauseOpt(ParamOwner.Type)
18731875
in.token match {
18741876
case EQUALS =>
18751877
in.nextToken()
1876-
TypeDef(name, tparams, typ()).withMods(mods)
1878+
TypeDef(name, tparams, typ()).withMods(mods).withComment(docstring)
18771879
case SUPERTYPE | SUBTYPE | SEMI | NEWLINE | NEWLINES | COMMA | RBRACE | EOF =>
18781880
TypeDef(name, tparams, typeBounds()).withMods(mods)
18791881
case _ =>

test/test/DottyDocTests.scala

Lines changed: 137 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,18 +42,22 @@ trait DottyDocTest extends DottyTest { self =>
4242
assert(false, s"""No docstring found, expected: "$expected"""")
4343
}
4444

45-
def run(): Unit = {
45+
def run(): Unit = try {
4646
val c = compiler(assertion)
4747
c.rootContext(ctx)
4848
c.newRun.compile(source)
4949
println(s"${self.getClass.getSimpleName.split("\\$").last} passed")
50+
} catch { case e: Throwable =>
51+
Console.err.println(s"${self.getClass.getSimpleName.split("\\$").last} failed")
52+
throw e
5053
}
5154
}
5255

5356
/** Add tests to the `tests` sequence */
5457
object DottyDocTests extends DottyTest {
5558
private[this] val tests = Seq(
5659
NoComment,
60+
5761
SingleClassInPackage,
5862
MultipleOpenedOnSingleClassInPackage,
5963
MultipleClassesInPackage,
@@ -67,13 +71,18 @@ object DottyDocTests extends DottyTest {
6771
ObjectsNestedClass,
6872
PackageObject,
6973
MultipleDocStringsBeforeEntity,
70-
MultipleDocStringsBeforeAndAfter
74+
MultipleDocStringsBeforeAndAfter,
75+
76+
ValuesWithDocString,
77+
VarsWithDocString,
78+
DefsWithDocString,
79+
TypesWithDocString
7180
)
7281

7382
def main(args: Array[String]): Unit = {
74-
println("------------ Testing DottyDoc ------------")
83+
println(s"-------------- Testing DottyDoc (${tests.length} tests) --------------")
7584
tests.foreach(_.run)
76-
println("--------- DottyDoc tests passed! ----------")
85+
println("--------------- DottyDoc tests passed! -------------------")
7786
}
7887
}
7988

@@ -371,3 +380,127 @@ case object MultipleDocStringsBeforeAndAfter extends DottyDocTest {
371380
}
372381

373382
}
383+
384+
case object ValuesWithDocString extends DottyDocTest {
385+
override val source =
386+
"""
387+
|object Object {
388+
| /** val1 */
389+
| val val1 = 1
390+
|
391+
| /** val2 */
392+
| val val2: Int = 2
393+
| /** bogus docstring */
394+
|
395+
| /** bogus docstring */
396+
| /** val3 */
397+
| val val3: List[Int] = 1 :: 2 :: 3 :: Nil
398+
|}
399+
""".stripMargin
400+
401+
import dotty.tools.dotc.ast.untpd._
402+
override def assertion = {
403+
case PackageDef(_, Seq(o: ModuleDef)) =>
404+
o.impl.body match {
405+
case (v1: MemberDef) :: (v2: MemberDef) :: (v3: MemberDef) :: Nil => {
406+
checkDocString(v1.rawComment, "/** val1 */")
407+
checkDocString(v2.rawComment, "/** val2 */")
408+
checkDocString(v3.rawComment, "/** val3 */")
409+
}
410+
case _ => assert(false, "Incorrect structure inside object")
411+
}
412+
}
413+
}
414+
415+
case object VarsWithDocString extends DottyDocTest {
416+
override val source =
417+
"""
418+
|object Object {
419+
| /** var1 */
420+
| var var1 = 1
421+
|
422+
| /** var2 */
423+
| var var2: Int = 2
424+
| /** bogus docstring */
425+
|
426+
| /** bogus docstring */
427+
| /** var3 */
428+
| var var3: List[Int] = 1 :: 2 :: 3 :: Nil
429+
|}
430+
""".stripMargin
431+
432+
import dotty.tools.dotc.ast.untpd._
433+
override def assertion = {
434+
case PackageDef(_, Seq(o: ModuleDef)) =>
435+
o.impl.body match {
436+
case (v1: MemberDef) :: (v2: MemberDef) :: (v3: MemberDef) :: Nil => {
437+
checkDocString(v1.rawComment, "/** var1 */")
438+
checkDocString(v2.rawComment, "/** var2 */")
439+
checkDocString(v3.rawComment, "/** var3 */")
440+
}
441+
case _ => assert(false, "Incorrect structure inside object")
442+
}
443+
}
444+
}
445+
446+
case object DefsWithDocString extends DottyDocTest {
447+
override val source =
448+
"""
449+
|object Object {
450+
| /** def1 */
451+
| def def1 = 1
452+
|
453+
| /** def2 */
454+
| def def2: Int = 2
455+
| /** bogus docstring */
456+
|
457+
| /** bogus docstring */
458+
| /** def3 */
459+
| def def3: List[Int] = 1 :: 2 :: 3 :: Nil
460+
|}
461+
""".stripMargin
462+
463+
import dotty.tools.dotc.ast.untpd._
464+
override def assertion = {
465+
case PackageDef(_, Seq(o: ModuleDef)) =>
466+
o.impl.body match {
467+
case (v1: MemberDef) :: (v2: MemberDef) :: (v3: MemberDef) :: Nil => {
468+
checkDocString(v1.rawComment, "/** def1 */")
469+
checkDocString(v2.rawComment, "/** def2 */")
470+
checkDocString(v3.rawComment, "/** def3 */")
471+
}
472+
case _ => assert(false, "Incorrect structure inside object")
473+
}
474+
}
475+
}
476+
477+
case object TypesWithDocString extends DottyDocTest {
478+
override val source =
479+
"""
480+
|object Object {
481+
| /** type1 */
482+
| type T1 = Int
483+
|
484+
| /** type2 */
485+
| type T2 = String
486+
| /** bogus docstring */
487+
|
488+
| /** bogus docstring */
489+
| /** type3 */
490+
| type T3 = T2
491+
|}
492+
""".stripMargin
493+
494+
import dotty.tools.dotc.ast.untpd._
495+
override def assertion = {
496+
case PackageDef(_, Seq(o: ModuleDef)) =>
497+
o.impl.body match {
498+
case (v1: MemberDef) :: (v2: MemberDef) :: (v3: MemberDef) :: Nil => {
499+
checkDocString(v1.rawComment, "/** type1 */")
500+
checkDocString(v2.rawComment, "/** type2 */")
501+
checkDocString(v3.rawComment, "/** type3 */")
502+
}
503+
case _ => assert(false, "Incorrect structure inside object")
504+
}
505+
}
506+
}

0 commit comments

Comments
 (0)