aboutsummaryrefslogtreecommitdiff
path: root/dottydoc
diff options
context:
space:
mode:
authorFelix Mulder <felix.mulder@gmail.com>2016-08-27 15:41:32 +0200
committerFelix Mulder <felix.mulder@gmail.com>2016-10-06 17:45:14 +0200
commit49b19933dc23220e582016fc0bfd0b35961d61a1 (patch)
tree6835c10369db7e42302cd1889b4807f06ce48911 /dottydoc
parent8be7177a5f2f369b4932e54ee888c36544e9d3a5 (diff)
downloaddotty-49b19933dc23220e582016fc0bfd0b35961d61a1.tar.gz
dotty-49b19933dc23220e582016fc0bfd0b35961d61a1.tar.bz2
dotty-49b19933dc23220e582016fc0bfd0b35961d61a1.zip
Move docstring cooking to dotty
Diffstat (limited to 'dottydoc')
-rw-r--r--dottydoc/src/dotty/tools/dottydoc/core/DocstringPhase.scala4
-rw-r--r--dottydoc/src/dotty/tools/dottydoc/core/UsecasePhase.scala20
-rw-r--r--dottydoc/src/dotty/tools/dottydoc/model/comment/CommentExpander.scala344
-rw-r--r--dottydoc/src/dotty/tools/dottydoc/model/comment/CommentUtils.scala224
-rw-r--r--dottydoc/test/UsecaseTest.scala37
5 files changed, 49 insertions, 580 deletions
diff --git a/dottydoc/src/dotty/tools/dottydoc/core/DocstringPhase.scala b/dottydoc/src/dotty/tools/dottydoc/core/DocstringPhase.scala
index 830336ba1..93d51503f 100644
--- a/dottydoc/src/dotty/tools/dottydoc/core/DocstringPhase.scala
+++ b/dottydoc/src/dotty/tools/dottydoc/core/DocstringPhase.scala
@@ -3,14 +3,10 @@ package dottydoc
package core
import dotc.core.Contexts.Context
-import dotc.ast.tpd
-
import transform.DocMiniPhase
import model._
import model.internal._
-import model.factories._
import model.comment._
-import dotty.tools.dotc.core.Symbols.Symbol
import BodyParsers._
class DocstringPhase extends DocMiniPhase with CommentParser with CommentCleaner {
diff --git a/dottydoc/src/dotty/tools/dottydoc/core/UsecasePhase.scala b/dottydoc/src/dotty/tools/dottydoc/core/UsecasePhase.scala
index 4d9c0abbd..8e9e1fd57 100644
--- a/dottydoc/src/dotty/tools/dottydoc/core/UsecasePhase.scala
+++ b/dottydoc/src/dotty/tools/dottydoc/core/UsecasePhase.scala
@@ -11,14 +11,18 @@ 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) = DefImpl(
- sym,
- d.name.show.split("\\$").head, // UseCase defs get $pos appended to their names
- flags(d), path(d.symbol),
- returnType(d.tpt.tpe),
- typeParams(d.symbol),
- paramLists(d.symbol.info)
- )
+ 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)
diff --git a/dottydoc/src/dotty/tools/dottydoc/model/comment/CommentExpander.scala b/dottydoc/src/dotty/tools/dottydoc/model/comment/CommentExpander.scala
deleted file mode 100644
index ece0d1018..000000000
--- a/dottydoc/src/dotty/tools/dottydoc/model/comment/CommentExpander.scala
+++ /dev/null
@@ -1,344 +0,0 @@
-/*
- * Port of DocComment.scala from nsc
- * @author Martin Odersky
- * @author Felix Mulder
- */
-
-package dotty.tools
-package dottydoc
-package model
-package comment
-
-import dotc.config.Printers.dottydoc
-import dotc.core.Contexts.Context
-import dotc.core.Symbols._
-import dotc.core.Flags
-import dotc.util.Positions._
-
-import scala.collection.mutable
-
-trait CommentExpander {
- import CommentUtils._
-
- def expand(sym: Symbol, site: Symbol)(implicit ctx: Context): String = {
- val parent = if (site != NoSymbol) site else sym
- defineVariables(parent)
- expandedDocComment(sym, parent)
- }
-
- /** The cooked doc comment of symbol `sym` after variable expansion, or "" if missing.
- *
- * @param sym The symbol for which doc comment is returned
- * @param site The class for which doc comments are generated
- * @throws ExpansionLimitExceeded when more than 10 successive expansions
- * of the same string are done, which is
- * interpreted as a recursive variable definition.
- */
- def expandedDocComment(sym: Symbol, site: Symbol, docStr: String = "")(implicit ctx: Context): String = {
- // when parsing a top level class or module, use the (module-)class itself to look up variable definitions
- val parent = if ((sym.is(Flags.Module) || sym.isClass) && site.is(Flags.Package)) sym
- else site
- expandVariables(cookedDocComment(sym, docStr), sym, parent)
- }
-
- private def template(raw: String): String = {
- val sections = tagIndex(raw)
-
- val defines = sections filter { startsWithTag(raw, _, "@define") }
- val usecases = sections filter { startsWithTag(raw, _, "@usecase") }
-
- val end = startTag(raw, (defines /*::: usecases*/).sortBy(_._1))
-
- if (end == raw.length - 2) raw else raw.substring(0, end) + "*/"
- }
-
- def defines(raw: String): List[String] = {
- val sections = tagIndex(raw)
- val defines = sections filter { startsWithTag(raw, _, "@define") }
- val usecases = sections filter { startsWithTag(raw, _, "@usecase") }
- val end = startTag(raw, (defines ::: usecases).sortBy(_._1))
-
- defines map { case (start, end) => raw.substring(start, end) }
- }
-
- private def replaceInheritDocToInheritdoc(docStr: String): String =
- docStr.replaceAll("""\{@inheritDoc\p{Zs}*\}""", "@inheritdoc")
-
- /** The cooked doc comment of an overridden symbol */
- protected def superComment(sym: Symbol)(implicit ctx: Context): Option[String] =
- allInheritedOverriddenSymbols(sym).iterator map (x => cookedDocComment(x)) find (_ != "")
-
- private val cookedDocComments = mutable.HashMap[Symbol, String]()
-
- /** The raw doc comment of symbol `sym`, minus usecase and define sections, augmented by
- * missing sections of an inherited doc comment.
- * If a symbol does not have a doc comment but some overridden version of it does,
- * the doc comment of the overridden version is copied instead.
- */
- def cookedDocComment(sym: Symbol, docStr: String = "")(implicit ctx: Context): String = cookedDocComments.getOrElseUpdate(sym, {
- var ownComment =
- if (docStr.length == 0) ctx.docbase.docstring(sym).map(c => template(c.raw)).getOrElse("")
- else template(docStr)
- ownComment = replaceInheritDocToInheritdoc(ownComment)
-
- superComment(sym) match {
- case None =>
- // SI-8210 - The warning would be false negative when this symbol is a setter
- if (ownComment.indexOf("@inheritdoc") != -1 && ! sym.isSetter)
- dottydoc.println(s"${sym.pos}: the comment for ${sym} contains @inheritdoc, but no parent comment is available to inherit from.")
- ownComment.replaceAllLiterally("@inheritdoc", "<invalid inheritdoc annotation>")
- case Some(sc) =>
- if (ownComment == "") sc
- else expandInheritdoc(sc, merge(sc, ownComment, sym), sym)
- }
- })
-
- private def isMovable(str: String, sec: (Int, Int)): Boolean =
- startsWithTag(str, sec, "@param") ||
- startsWithTag(str, sec, "@tparam") ||
- startsWithTag(str, sec, "@return")
-
- def merge(src: String, dst: String, sym: Symbol, copyFirstPara: Boolean = false): String = {
- val srcSections = tagIndex(src)
- val dstSections = tagIndex(dst)
- val srcParams = paramDocs(src, "@param", srcSections)
- val dstParams = paramDocs(dst, "@param", dstSections)
- val srcTParams = paramDocs(src, "@tparam", srcSections)
- val dstTParams = paramDocs(dst, "@tparam", dstSections)
- val out = new StringBuilder
- var copied = 0
- var tocopy = startTag(dst, dstSections dropWhile (!isMovable(dst, _)))
-
- if (copyFirstPara) {
- val eop = // end of comment body (first para), which is delimited by blank line, or tag, or end of comment
- (findNext(src, 0)(src.charAt(_) == '\n')) min startTag(src, srcSections)
- out append src.substring(0, eop).trim
- copied = 3
- tocopy = 3
- }
-
- def mergeSection(srcSec: Option[(Int, Int)], dstSec: Option[(Int, Int)]) = dstSec match {
- case Some((start, end)) =>
- if (end > tocopy) tocopy = end
- case None =>
- srcSec match {
- case Some((start1, end1)) => {
- out append dst.substring(copied, tocopy).trim
- out append "\n"
- copied = tocopy
- out append src.substring(start1, end1).trim
- }
- case None =>
- }
- }
-
- //TODO: enable this once you know how to get `sym.paramss`
- /*
- for (params <- sym.paramss; param <- params)
- mergeSection(srcParams get param.name.toString, dstParams get param.name.toString)
- for (tparam <- sym.typeParams)
- mergeSection(srcTParams get tparam.name.toString, dstTParams get tparam.name.toString)
-
- mergeSection(returnDoc(src, srcSections), returnDoc(dst, dstSections))
- mergeSection(groupDoc(src, srcSections), groupDoc(dst, dstSections))
- */
-
- if (out.length == 0) dst
- else {
- out append dst.substring(copied)
- out.toString
- }
- }
-
- /**
- * Expand inheritdoc tags
- * - for the main comment we transform the inheritdoc into the super variable,
- * and the variable expansion can expand it further
- * - for the param, tparam and throws sections we must replace comments on the spot
- *
- * This is done separately, for two reasons:
- * 1. It takes longer to run compared to merge
- * 2. The inheritdoc annotation should not be used very often, as building the comment from pieces severely
- * impacts performance
- *
- * @param parent The source (or parent) comment
- * @param child The child (overriding member or usecase) comment
- * @param sym The child symbol
- * @return The child comment with the inheritdoc sections expanded
- */
- def expandInheritdoc(parent: String, child: String, sym: Symbol): String =
- if (child.indexOf("@inheritdoc") == -1)
- child
- else {
- val parentSections = tagIndex(parent)
- val childSections = tagIndex(child)
- val parentTagMap = sectionTagMap(parent, parentSections)
- val parentNamedParams = Map() +
- ("@param" -> paramDocs(parent, "@param", parentSections)) +
- ("@tparam" -> paramDocs(parent, "@tparam", parentSections)) +
- ("@throws" -> paramDocs(parent, "@throws", parentSections))
-
- val out = new StringBuilder
-
- def replaceInheritdoc(childSection: String, parentSection: => String) =
- if (childSection.indexOf("@inheritdoc") == -1)
- childSection
- else
- childSection.replaceAllLiterally("@inheritdoc", parentSection)
-
- def getParentSection(section: (Int, Int)): String = {
-
- def getSectionHeader = extractSectionTag(child, section) match {
- case param@("@param"|"@tparam"|"@throws") => param + " " + extractSectionParam(child, section)
- case other => other
- }
-
- def sectionString(param: String, paramMap: Map[String, (Int, Int)]): String =
- paramMap.get(param) match {
- case Some(section) =>
- // Cleanup the section tag and parameter
- val sectionTextBounds = extractSectionText(parent, section)
- cleanupSectionText(parent.substring(sectionTextBounds._1, sectionTextBounds._2))
- case None =>
- dottydoc.println(s"""${sym.pos}: the """" + getSectionHeader + "\" annotation of the " + sym +
- " comment contains @inheritdoc, but the corresponding section in the parent is not defined.")
- "<invalid inheritdoc annotation>"
- }
-
- child.substring(section._1, section._1 + 7) match {
- case param@("@param "|"@tparam"|"@throws") =>
- sectionString(extractSectionParam(child, section), parentNamedParams(param.trim))
- case _ =>
- sectionString(extractSectionTag(child, section), parentTagMap)
- }
- }
-
- def mainComment(str: String, sections: List[(Int, Int)]): String =
- if (str.trim.length > 3)
- str.trim.substring(3, startTag(str, sections))
- else
- ""
-
- // Append main comment
- out.append("/**")
- out.append(replaceInheritdoc(mainComment(child, childSections), mainComment(parent, parentSections)))
-
- // Append sections
- for (section <- childSections)
- out.append(replaceInheritdoc(child.substring(section._1, section._2), getParentSection(section)))
-
- out.append("*/")
- out.toString
- }
-
- protected def expandVariables(initialStr: String, sym: Symbol, site: Symbol)(implicit ctx: Context): String = {
- val expandLimit = 10
-
- def expandInternal(str: String, depth: Int): String = {
- if (depth >= expandLimit)
- throw new ExpansionLimitExceeded(str)
-
- val out = new StringBuilder
- var copied, idx = 0
- // excluding variables written as \$foo so we can use them when
- // necessary to document things like Symbol#decode
- def isEscaped = idx > 0 && str.charAt(idx - 1) == '\\'
- while (idx < str.length) {
- if ((str charAt idx) != '$' || isEscaped)
- idx += 1
- else {
- val vstart = idx
- idx = skipVariable(str, idx + 1)
- def replaceWith(repl: String) {
- out append str.substring(copied, vstart)
- out append repl
- copied = idx
- }
- variableName(str.substring(vstart + 1, idx)) match {
- case "super" =>
- superComment(sym) foreach { sc =>
- val superSections = tagIndex(sc)
- replaceWith(sc.substring(3, startTag(sc, superSections)))
- for (sec @ (start, end) <- superSections)
- if (!isMovable(sc, sec)) out append sc.substring(start, end)
- }
- case "" => idx += 1
- case vname =>
- lookupVariable(vname, site) match {
- case Some(replacement) => replaceWith(replacement)
- case None =>
- dottydoc.println(s"Variable $vname undefined in comment for $sym in $site")
- }
- }
- }
- }
- if (out.length == 0) str
- else {
- out append str.substring(copied)
- expandInternal(out.toString, depth + 1)
- }
- }
-
- // We suppressed expanding \$ throughout the recursion, and now we
- // need to replace \$ with $ so it looks as intended.
- expandInternal(initialStr, 0).replaceAllLiterally("""\$""", "$")
- }
-
- def defineVariables(sym: Symbol)(implicit ctx: Context) = {
- val Trim = "(?s)^[\\s&&[^\n\r]]*(.*?)\\s*$".r
-
- val raw = ctx.docbase.docstring(sym).map(_.raw).getOrElse("")
- defs(sym) ++= defines(raw).map {
- str => {
- val start = skipWhitespace(str, "@define".length)
- val (key, value) = str.splitAt(skipVariable(str, start))
- key.drop(start) -> value
- }
- } map {
- case (key, Trim(value)) =>
- variableName(key) -> value.replaceAll("\\s+\\*+$", "")
- }
- }
-
- /** Maps symbols to the variable -> replacement maps that are defined
- * in their doc comments
- */
- private val defs = mutable.HashMap[Symbol, Map[String, String]]() withDefaultValue Map()
-
- /** Lookup definition of variable.
- *
- * @param vble The variable for which a definition is searched
- * @param site The class for which doc comments are generated
- */
- def lookupVariable(vble: String, site: Symbol)(implicit ctx: Context): Option[String] = site match {
- case NoSymbol => None
- case _ =>
- val searchList =
- if (site.flags.is(Flags.Module)) site :: site.info.baseClasses
- else site.info.baseClasses
-
- searchList collectFirst { case x if defs(x) contains vble => defs(x)(vble) } match {
- case Some(str) if str startsWith "$" => lookupVariable(str.tail, site)
- case res => res orElse lookupVariable(vble, site.owner)
- }
- }
-
- /** The position of the raw doc comment of symbol `sym`, or NoPosition if missing
- * If a symbol does not have a doc comment but some overridden version of it does,
- * the position of the doc comment of the overridden version is returned instead.
- */
- def docCommentPos(sym: Symbol)(implicit ctx: Context): Position =
- ctx.docbase.docstring(sym).map(_.pos).getOrElse(NoPosition)
-
- /** A version which doesn't consider self types, as a temporary measure:
- * an infinite loop has broken out between superComment and cookedDocComment
- * since r23926.
- */
- private def allInheritedOverriddenSymbols(sym: Symbol)(implicit ctx: Context): List[Symbol] = {
- if (!sym.owner.isClass) Nil
- else sym.allOverriddenSymbols.toList.filter(_ != NoSymbol) //TODO: could also be `sym.owner.allOverrid..`
- //else sym.owner.ancestors map (sym overriddenSymbol _) filter (_ != NoSymbol)
- }
-
- class ExpansionLimitExceeded(str: String) extends Exception
-}
diff --git a/dottydoc/src/dotty/tools/dottydoc/model/comment/CommentUtils.scala b/dottydoc/src/dotty/tools/dottydoc/model/comment/CommentUtils.scala
deleted file mode 100644
index e5307bd3c..000000000
--- a/dottydoc/src/dotty/tools/dottydoc/model/comment/CommentUtils.scala
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * Port of DocStrings.scala from nsc
- * @author Martin Odersky
- * @author Felix Mulder
- */
-
-package dotty.tools
-package dottydoc
-package model
-package comment
-
-import scala.reflect.internal.Chars._
-
-object CommentUtils {
-
- /** Returns index of string `str` following `start` skipping longest
- * sequence of whitespace characters characters (but no newlines)
- */
- def skipWhitespace(str: String, start: Int): Int =
- if (start < str.length && isWhitespace(str charAt start)) skipWhitespace(str, start + 1)
- else start
-
- /** Returns index of string `str` following `start` skipping
- * sequence of identifier characters.
- */
- def skipIdent(str: String, start: Int): Int =
- if (start < str.length && isIdentifierPart(str charAt start)) skipIdent(str, start + 1)
- else start
-
- /** Returns index of string `str` following `start` skipping
- * sequence of identifier characters.
- */
- def skipTag(str: String, start: Int): Int =
- if (start < str.length && (str charAt start) == '@') skipIdent(str, start + 1)
- else start
-
-
- /** Returns index of string `str` after `start` skipping longest
- * sequence of space and tab characters, possibly also containing
- * a single `*` character or the `/``**` sequence.
- * @pre start == str.length || str(start) == `\n`
- */
- def skipLineLead(str: String, start: Int): Int =
- if (start == str.length) start
- else {
- val idx = skipWhitespace(str, start + 1)
- if (idx < str.length && (str charAt idx) == '*') skipWhitespace(str, idx + 1)
- else if (idx + 2 < str.length && (str charAt idx) == '/' && (str charAt (idx + 1)) == '*' && (str charAt (idx + 2)) == '*')
- skipWhitespace(str, idx + 3)
- else idx
- }
-
- /** Skips to next occurrence of `\n` or to the position after the `/``**` sequence following index `start`.
- */
- def skipToEol(str: String, start: Int): Int =
- if (start + 2 < str.length && (str charAt start) == '/' && (str charAt (start + 1)) == '*' && (str charAt (start + 2)) == '*') start + 3
- else if (start < str.length && (str charAt start) != '\n') skipToEol(str, start + 1)
- else start
-
- /** Returns first index following `start` and starting a line (i.e. after skipLineLead) or starting the comment
- * which satisfies predicate `p`.
- */
- def findNext(str: String, start: Int)(p: Int => Boolean): Int = {
- val idx = skipLineLead(str, skipToEol(str, start))
- if (idx < str.length && !p(idx)) findNext(str, idx)(p)
- else idx
- }
-
- /** Return first index following `start` and starting a line (i.e. after skipLineLead)
- * which satisfies predicate `p`.
- */
- def findAll(str: String, start: Int)(p: Int => Boolean): List[Int] = {
- val idx = findNext(str, start)(p)
- if (idx == str.length) List()
- else idx :: findAll(str, idx)(p)
- }
-
- /** Produces a string index, which is a list of `sections`, i.e
- * pairs of start/end positions of all tagged sections in the string.
- * Every section starts with an at sign and extends to the next at sign,
- * or to the end of the comment string, but excluding the final two
- * characters which terminate the comment.
- *
- * Also take usecases into account - they need to expand until the next
- * usecase or the end of the string, as they might include other sections
- * of their own
- */
- def tagIndex(str: String, p: Int => Boolean = (idx => true)): List[(Int, Int)] = {
- var indices = findAll(str, 0) (idx => str(idx) == '@' && p(idx))
- indices = mergeUsecaseSections(str, indices)
- indices = mergeInheritdocSections(str, indices)
-
- indices match {
- case List() => List()
- case idxs => idxs zip (idxs.tail ::: List(str.length - 2))
- }
- }
-
- /**
- * Merge sections following an usecase into the usecase comment, so they
- * can override the parent symbol's sections
- */
- def mergeUsecaseSections(str: String, idxs: List[Int]): List[Int] = {
- idxs.indexWhere(str.startsWith("@usecase", _)) match {
- case firstUCIndex if firstUCIndex != -1 =>
- val commentSections = idxs.take(firstUCIndex)
- val usecaseSections = idxs.drop(firstUCIndex).filter(str.startsWith("@usecase", _))
- commentSections ::: usecaseSections
- case _ =>
- idxs
- }
- }
-
- /**
- * Merge the inheritdoc sections, as they never make sense on their own
- */
- def mergeInheritdocSections(str: String, idxs: List[Int]): List[Int] =
- idxs.filterNot(str.startsWith("@inheritdoc", _))
-
- /** Does interval `iv` start with given `tag`?
- */
- def startsWithTag(str: String, section: (Int, Int), tag: String): Boolean =
- startsWithTag(str, section._1, tag)
-
- def startsWithTag(str: String, start: Int, tag: String): Boolean =
- str.startsWith(tag, start) && !isIdentifierPart(str charAt (start + tag.length))
-
- /** The first start tag of a list of tag intervals,
- * or the end of the whole comment string - 2 if list is empty
- */
- def startTag(str: String, sections: List[(Int, Int)]) = sections match {
- case Nil => str.length - 2
- case (start, _) :: _ => start
- }
-
- /** A map from parameter names to start/end indices describing all parameter
- * sections in `str` tagged with `tag`, where `sections` is the index of `str`.
- */
- def paramDocs(str: String, tag: String, sections: List[(Int, Int)]): Map[String, (Int, Int)] =
- Map() ++ {
- for (section <- sections if startsWithTag(str, section, tag)) yield {
- val start = skipWhitespace(str, section._1 + tag.length)
- str.substring(start, skipIdent(str, start)) -> section
- }
- }
-
- /** Optionally start and end index of return section in `str`, or `None`
- * if `str` does not have a @group. */
- def groupDoc(str: String, sections: List[(Int, Int)]): Option[(Int, Int)] =
- sections find (startsWithTag(str, _, "@group"))
-
-
- /** Optionally start and end index of return section in `str`, or `None`
- * if `str` does not have a @return.
- */
- def returnDoc(str: String, sections: List[(Int, Int)]): Option[(Int, Int)] =
- sections find (startsWithTag(str, _, "@return"))
-
- /** Extracts variable name from a string, stripping any pair of surrounding braces */
- def variableName(str: String): String =
- if (str.length >= 2 && (str charAt 0) == '{' && (str charAt (str.length - 1)) == '}')
- str.substring(1, str.length - 1)
- else
- str
-
- /** Returns index following variable, or start index if no variable was recognized
- */
- def skipVariable(str: String, start: Int): Int = {
- var idx = start
- if (idx < str.length && (str charAt idx) == '{') {
- do idx += 1
- while (idx < str.length && (str charAt idx) != '}')
- if (idx < str.length) idx + 1 else start
- } else {
- while (idx < str.length && isVarPart(str charAt idx))
- idx += 1
- idx
- }
- }
-
- /** A map from the section tag to section parameters */
- def sectionTagMap(str: String, sections: List[(Int, Int)]): Map[String, (Int, Int)] =
- Map() ++ {
- for (section <- sections) yield
- extractSectionTag(str, section) -> section
- }
-
- /** Extract the section tag, treating the section tag as an identifier */
- def extractSectionTag(str: String, section: (Int, Int)): String =
- str.substring(section._1, skipTag(str, section._1))
-
- /** Extract the section parameter */
- def extractSectionParam(str: String, section: (Int, Int)): String = {
- val (beg, _) = section
- assert(str.startsWith("@param", beg) ||
- str.startsWith("@tparam", beg) ||
- str.startsWith("@throws", beg))
-
- val start = skipWhitespace(str, skipTag(str, beg))
- val finish = skipIdent(str, start)
-
- str.substring(start, finish)
- }
-
- /** Extract the section text, except for the tag and comment newlines */
- def extractSectionText(str: String, section: (Int, Int)): (Int, Int) = {
- val (beg, end) = section
- if (str.startsWith("@param", beg) ||
- str.startsWith("@tparam", beg) ||
- str.startsWith("@throws", beg))
- (skipWhitespace(str, skipIdent(str, skipWhitespace(str, skipTag(str, beg)))), end)
- else
- (skipWhitespace(str, skipTag(str, beg)), end)
- }
-
- /** Cleanup section text */
- def cleanupSectionText(str: String) = {
- var result = str.trim.replaceAll("\n\\s+\\*\\s+", " \n")
- while (result.endsWith("\n"))
- result = result.substring(0, str.length - 1)
- result
- }
-
-}
diff --git a/dottydoc/test/UsecaseTest.scala b/dottydoc/test/UsecaseTest.scala
index 05bc8663f..c7b398d1f 100644
--- a/dottydoc/test/UsecaseTest.scala
+++ b/dottydoc/test/UsecaseTest.scala
@@ -31,6 +31,8 @@ class UsecaseTest extends DottyTest {
case PackageImpl(_, _, List(trt: Trait), _, _) =>
val List(foo: Def) = trt.members
+ assert(foo.comment.isDefined, "Lost comment in transformations")
+
val returnValue = foo.returnValue match {
case ref: TypeReference => ref.title
case _ =>
@@ -184,6 +186,41 @@ class UsecaseTest extends DottyTest {
}
}
+ @Test def checkStripping = {
+ val source = new SourceFile(
+ "CheckStripping.scala",
+ """
+ |package scala
+ |
+ |/** The trait $Coll
+ | *
+ | * @define Coll Iterable
+ | */
+ |trait Iterable[A] {
+ | /** Definition with a "disturbing" signature
+ | *
+ | * @usecase def map[B](f: A => B): $Coll[B]
+ | */
+ | def map[B, M[B]](f: A => B): M[B] = ???
+ |}
+ """.stripMargin
+ )
+
+ checkSources(source :: Nil) { packages =>
+ packages("scala") match {
+ case PackageImpl(_, _, List(trt: Trait), _, _) =>
+ val List(map: Def) = trt.members
+ assert(map.comment.isDefined, "Lost comment in transformations")
+
+ val docstr = ctx.docbase.docstring(map.symbol).get.raw
+ assert(
+ !docstr.contains("@usecase"),
+ s"Comment should not contain usecase after stripping, but was:\n$docstr"
+ )
+ }
+ }
+ }
+
@Test def checkIterator =
checkFiles("./scala-scala/src/library/scala/collection/Iterator.scala" :: Nil) { _ =>
// success if typer throws no errors! :)