Skip to content

Scala3doc: cook comments #10506

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

Merged
merged 5 commits into from
Nov 27, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions compiler/src/dotty/tools/dotc/core/Comments.scala
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,13 @@ object Comments {
* @param expanded If this comment has been expanded, it's expansion, otherwise `None`.
* @param usecases The usecases for this comment.
*/
final case class Comment(span: Span, raw: String, expanded: Option[String], usecases: List[UseCase]) {
final case class Comment(
span: Span,
raw: String,
expanded: Option[String],
usecases: List[UseCase],
variables: Map[String, String],
) {

/** Has this comment been cooked or expanded? */
def isExpanded: Boolean = expanded.isDefined
Expand All @@ -65,7 +71,7 @@ object Comments {
def expand(f: String => String)(using Context): Comment = {
val expandedComment = f(raw)
val useCases = Comment.parseUsecases(expandedComment, span)
Comment(span, raw, Some(expandedComment), useCases)
Comment(span, raw, Some(expandedComment), useCases, Map.empty)
}
}

Expand All @@ -74,7 +80,7 @@ object Comments {
def isDocComment(comment: String): Boolean = comment.startsWith("/**")

def apply(span: Span, raw: String): Comment =
Comment(span, raw, None, Nil)
Comment(span, raw, None, Nil, Map.empty)

private def parseUsecases(expandedComment: String, span: Span)(using Context): List[UseCase] =
if (!isDocComment(expandedComment))
Expand Down
9 changes: 4 additions & 5 deletions compiler/src/dotty/tools/dotc/parsing/Scanners.scala
Original file line number Diff line number Diff line change
Expand Up @@ -190,11 +190,7 @@ object Scanners {
private def addComment(comment: Comment): Unit = {
val lookahead = lookaheadReader()
def nextPos: Int = (lookahead.getc(): @switch) match {
case ' ' | '\t' => nextPos
case CR | LF | FF =>
// if we encounter line delimiting whitespace we don't count it, since
// it seems not to affect positions in source
nextPos - 1
case ' ' | '\t' | CR | LF | FF => nextPos
case _ => lookahead.charOffset - 1
}
docstringMap = docstringMap + (nextPos -> comment)
Expand Down Expand Up @@ -854,6 +850,9 @@ object Scanners {

if (comment.isDocComment)
addComment(comment)
else
// "forward" doc comments over normal ones
getDocComment(start).foreach(addComment)
}

true
Expand Down
47 changes: 47 additions & 0 deletions compiler/test/dotty/tools/dotc/parsing/DocstringTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,37 @@ class DocstringTests extends DocstringTest {
}
}


@Test def overNL = {
val source =
"""
|/** Class1 */
|
|class Class1
""".stripMargin

import dotty.tools.dotc.ast.untpd._
checkFrontend(source) {
case p @ PackageDef(_, Seq(c: TypeDef)) =>
checkDocString(c.rawComment.map(_.raw), "/** Class1 */")
}
}

@Test def overComment = {
val source =
"""
|/** Class1 */
|// foo
|class Class1
""".stripMargin

import dotty.tools.dotc.ast.untpd._
checkFrontend(source) {
case p @ PackageDef(_, Seq(c: TypeDef)) =>
checkDocString(c.rawComment.map(_.raw), "/** Class1 */")
}
}

@Test def withAnnotation = {
val source =
"""
Expand All @@ -489,6 +520,22 @@ class DocstringTests extends DocstringTest {
}
}

@Test def withAnnotationOverComment = {
val source =
"""
|/** Class1 */
|// foo
|@SerialVersionUID(1)
|class Class1
""".stripMargin

import dotty.tools.dotc.ast.untpd._
checkFrontend(source) {
case p @ PackageDef(_, Seq(c: TypeDef)) =>
checkDocString(c.rawComment.map(_.raw), "/** Class1 */")
}
}

@Test def nestedComment = {
val source =
"""
Expand Down
26 changes: 23 additions & 3 deletions scala3doc-testcases/src/tests/tests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ package tests
* This is an *important* _test_ class.
* Important enough to get multiple sentences in its summary.
*
* Here is foo: $foo
*
* And `this` is inline code.
*
* And this is the **strong** __emphasis__ test.
Expand Down Expand Up @@ -56,17 +58,22 @@ package tests
* @version 1.0.0
* @result A class doesn't actually have a result.
* @constructor A class has a constructor, and this one is important.
*
* @define foo Foo expanded.
*/
class A {

/** This is a method.
/** This is my method.
*
* This is a link: [[AA]].
*
* This is another link: [[AA$]].
*
* And yet another: [[B]].
*/
final def myMethod(s: String): String = s

/** This is foo: $foo */
def method(s: String): String = s

class AA
Expand All @@ -85,6 +92,8 @@ object A
*
* This is an ''important'' '''test''' __class__. And `this` is inline code.
*
* Here is foo: $foo
*
* While
* {{{
* this.is("a code block")
Expand All @@ -104,9 +113,12 @@ object A
*
* And this is his companion: [[tests.A$]].
* @syntax wiki
* @define foo Bar, actually.
*/
class B extends A {
/** This is a method. */
/** @inheritdoc */ override def method(s: String): String = s

/** This is my foo: $foo */
def otherMethod(s: String): String = s

class BB
Expand All @@ -127,7 +139,8 @@ object B {
val Z: Int = 0
}

class C {
/** This is foo: $foo */
class C extends A {
object CC
class CC
}
Expand Down Expand Up @@ -192,3 +205,10 @@ class Methods:
def primitives(a: Int, b: Double, c: Short): Byte = 0
def strings(a: String): String = ""
def arrays(a: Array[String], b: Array[Int]): Array[Double] = ???

/** @define foo O's foo.
*/
object O:

/** This is foo: $foo */
def method(s: String) = s
17 changes: 15 additions & 2 deletions scala3doc/src/dotty/dokka/tasty/ScalaDocSupport.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,24 @@ trait ScaladocSupport { self: TastyParser =>
import qctx.reflect._

def parseComment(
commentNode: Documentation,
commentPre: Documentation,
tree: Tree
): dkkd.DocumentationNode = {
val commentNode =
if tree.symbol.isClassDef || tree.symbol.owner.isClassDef then
import dotty.tools.dotc
given ctx as dotc.core.Contexts.Context = qctx.asInstanceOf[scala.quoted.runtime.impl.QuotesImpl].ctx

val sym = tree.symbol.asInstanceOf[dotc.core.Symbols.Symbol]

comments.CommentExpander.cookComment(sym)(using ctx)
.get.asInstanceOf[Documentation]
else
commentPre

val commentString = commentNode.expanded getOrElse commentNode.raw
val preparsed =
comments.Preparser.preparse(comments.Cleaner.clean(commentNode.raw))
comments.Preparser.preparse(comments.Cleaner.clean(commentString))

val commentSyntax =
preparsed.syntax.headOption match {
Expand Down
Loading