diff options
9 files changed, 503 insertions, 89 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/DocComments.scala b/src/compiler/scala/tools/nsc/ast/DocComments.scala index 6a6379cca2..678f7b3028 100755 --- a/src/compiler/scala/tools/nsc/ast/DocComments.scala +++ b/src/compiler/scala/tools/nsc/ast/DocComments.scala @@ -19,6 +19,8 @@ import scala.collection.mutable */ trait DocComments { self: Global => + var cookedDocComments = Map[Symbol, String]() + def reporter: Reporter /** The raw doc comment map */ @@ -50,21 +52,29 @@ trait DocComments { self: Global => else sym.owner.ancestors map (sym overriddenSymbol _) filter (_ != NoSymbol) } - /** The raw doc comment of symbol `sym`, minus @usecase and @define sections, augmented by + /** 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 = ""): String = { - val ownComment = if (docStr.length == 0) docComments get sym map (_.template) getOrElse "" - else DocComment(docStr).template - superComment(sym) match { - case None => - ownComment - case Some(sc) => - if (ownComment == "") sc - else merge(sc, ownComment, sym) - } + def cookedDocComment(sym: Symbol, docStr: String = ""): String = cookedDocComments.get(sym) match { + case Some(comment) => + comment + case None => + val ownComment = if (docStr.length == 0) docComments get sym map (_.template) getOrElse "" + else DocComment(docStr).template + val comment = superComment(sym) match { + case None => + if (ownComment.indexOf("@inheritdoc") != -1) + reporter.warning(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) + } + cookedDocComments += (sym -> comment) + comment } /** The cooked doc comment of symbol `sym` after variable expansion, or "" if missing. @@ -99,10 +109,18 @@ trait DocComments { self: Global => */ def useCases(sym: Symbol, site: Symbol): List[(Symbol, String, Position)] = { def getUseCases(dc: DocComment) = { - for (uc <- dc.useCases; defn <- uc.expandedDefs(sym, site)) yield - (defn, - expandVariables(merge(cookedDocComment(sym), uc.comment.raw, defn), sym, site), - uc.pos) + val fullSigComment = cookedDocComment(sym) + for (uc <- dc.useCases; defn <- uc.expandedDefs(sym, site)) yield { + // use cases comments go through a series of transformations: + // 1 - filling in missing sections from the full signature + // 2 - expanding explicit inheritance @inheritdoc tags + // 3 - expanding variables like $COLL + val useCaseCommentRaw = uc.comment.raw + val useCaseCommentMerged = merge(fullSigComment, useCaseCommentRaw, defn) + val useCaseCommentInheritdoc = expandInheritdoc(fullSigComment, useCaseCommentMerged, sym) + val useCaseCommentVariables = expandVariables(useCaseCommentInheritdoc, sym, site) + (defn, useCaseCommentVariables, uc.pos) + } } getDocComment(sym) map getUseCases getOrElse List() } @@ -201,6 +219,80 @@ trait DocComments { self: Global => } } + /** + * 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 + */ + def expandInheritdoc(src: String, dst: String, sym: Symbol): String = + if (dst.indexOf("@inheritdoc") == -1) + dst + else { + val srcSections = tagIndex(src) + val dstSections = tagIndex(dst) + val srcTagMap = sectionTagMap(src, srcSections) + val srcNamedParams = Map() + + ("@param" -> paramDocs(src, "@param", srcSections)) + + ("@tparam" -> paramDocs(src, "@tparam", srcSections)) + + ("@throws" -> paramDocs(src, "@throws", srcSections)) + + val out = new StringBuilder + + def replaceInheritdoc(src: String, dst: String) = + if (dst.indexOf("@inheritdoc") == -1) + dst + else + dst.replaceAllLiterally("@inheritdoc", src) + + def getSourceSection(section: (Int, Int)): String = { + + def getSectionHeader = extractSectionTag(dst, section) match { + case param@("@param"|"@tparam"|"@throws") => param + " " + extractSectionParam(dst, 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(src, section) + cleanupSectionText(src.substring(sectionTextBounds._1, sectionTextBounds._2)) + case None => + reporter.info(sym.pos, "The \"" + getSectionHeader + "\" annotation of the " + sym + + " comment contains @inheritdoc, but the corresponding section in the parent is not defined.", true) + "<invalid inheritdoc annotation>" + } + + dst.substring(section._1, section._1 + 7) match { + case param@("@param "|"@tparam"|"@throws") => sectionString(extractSectionParam(dst, section), srcNamedParams(param.trim)) + case _ => sectionString(extractSectionTag(dst, section), srcTagMap) + } + } + + 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(src, srcSections), mainComment(dst, dstSections))) + + // Append sections + for (section <- dstSections) + out.append(replaceInheritdoc(getSourceSection(section), dst.substring(section._1, section._2))) + + out.append("*/") + out.toString + } + /** Maps symbols to the variable -> replacement maps that are defined * in their doc comments */ diff --git a/src/compiler/scala/tools/nsc/doc/html/page/Template.scala b/src/compiler/scala/tools/nsc/doc/html/page/Template.scala index 5e5320ca9a..e35286b281 100644 --- a/src/compiler/scala/tools/nsc/doc/html/page/Template.scala +++ b/src/compiler/scala/tools/nsc/doc/html/page/Template.scala @@ -438,7 +438,9 @@ class Template(tpl: DocTemplateEntity) extends HtmlPage { if(!comment.throws.isEmpty) { <dt>Exceptions thrown</dt> <dd>{ - val exceptionsXml: Iterable[scala.xml.NodeSeq] = (for(exception <- comment.throws ) yield <span class="cmt">{Text(exception._1) ++ bodyToHtml(exception._2)}</span> ) + val exceptionsXml: Iterable[scala.xml.NodeSeq] = + for(exception <- comment.throws.toList.sortBy(_._1) ) yield + <span class="cmt">{Text(exception._1) ++ bodyToHtml(exception._2)}</span> exceptionsXml.reduceLeft(_ ++ Text("") ++ _) }</dd> } else NodeSeq.Empty diff --git a/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala b/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala index efa524503c..b088c643cb 100644 --- a/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala @@ -38,7 +38,7 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory => val key = (sym, inTpl) if (commentCache isDefinedAt key) Some(commentCache(key)) - else { // not reached for use-case comments + else { val c = defineComment(sym, inTpl) if (c isDefined) commentCache += (sym, inTpl) -> c.get c diff --git a/src/compiler/scala/tools/nsc/util/DocStrings.scala b/src/compiler/scala/tools/nsc/util/DocStrings.scala index fbe92e5d84..f4ce6d6ef1 100755 --- a/src/compiler/scala/tools/nsc/util/DocStrings.scala +++ b/src/compiler/scala/tools/nsc/util/DocStrings.scala @@ -26,6 +26,14 @@ object DocStrings { 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. @@ -68,38 +76,46 @@ object DocStrings { /** 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 a `@` and extends to the next `@`, or - * to the end of the comment string, but excluding the final two + * 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)] = - findAll(str, 0) (idx => str(idx) == '@' && p(idx)) match { + 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 => { - val idxs2 = mergeUsecaseSections(str, idxs) - idxs2 zip (idxs2.tail ::: List(str.length - 2)) - } + 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.find(str.substring(_).startsWith("@usecase")) match { - case Some(firstUC) => - val commentSections = idxs.take(idxs.indexOf(firstUC)) - val usecaseSections = idxs.drop(idxs.indexOf(firstUC)).filter(str.substring(_).startsWith("@usecase")) + idxs.indexWhere(str.substring(_).startsWith("@usecase")) match { + case firstUCIndex if firstUCIndex != -1 => + val commentSections = idxs.take(firstUCIndex) + val usecaseSections = idxs.drop(firstUCIndex).filter(str.substring(_).startsWith("@usecase")) commentSections ::: usecaseSections - case None => + 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.substring(_).startsWith("@inheritdoc")) + /** Does interval `iv` start with given `tag`? */ def startsWithTag(str: String, section: (Int, Int), tag: String): Boolean = @@ -108,12 +124,11 @@ object DocStrings { 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 List() => str.length - 2 + case Nil => str.length - 2 case (start, _) :: _ => start } @@ -155,4 +170,46 @@ object DocStrings { 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 indentifier */ + 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 = { + assert(str.substring(section._1).startsWith("@param") || + str.substring(section._1).startsWith("@tparam") || + str.substring(section._1).startsWith("@throws")) + + val start = skipWhitespace(str, skipTag(str, section._1)) + 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) = { + if (str.substring(section._1).startsWith("@param") || + str.substring(section._1).startsWith("@tparam") || + str.substring(section._1).startsWith("@throws")) + (skipWhitespace(str, skipIdent(str, skipWhitespace(str, skipTag(str, section._1)))), section._2) + else + (skipWhitespace(str, skipTag(str, section._1)), section._2) + } + + /** 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/test/scaladoc/resources/explicit-inheritance-override.scala b/test/scaladoc/resources/explicit-inheritance-override.scala new file mode 100644 index 0000000000..62ce653aea --- /dev/null +++ b/test/scaladoc/resources/explicit-inheritance-override.scala @@ -0,0 +1,48 @@ +// This tests the implicit comment inheritance capabilities of scaladoc for class inheritance (no $super, no @inheritdoc) +class InheritDocBase { + /** + * The base comment. And another sentence... + * + * @param arg1 The T term comment + * @param arg2 The string comment + * @tparam T the type of the first argument + * @throws SomeException if the function is not called with correct parameters + * @return The return comment + * @see The Manual + * @note Be careful! + * @example function[Int](3, "something") + * @author a Scala developer + * @version 0.0.2 + * @since 0.0.1 + * @todo Call mom. + */ + def function[T](arg1: T, arg2: String): Double = 0.0d +} + +class InheritDocDerived extends InheritDocBase { + /** + * Starting line + * + * @inheritdoc + * @inheritdoc + * + * Ending line + * + * @param arg1 Start1 @inheritdoc End1 + * @param arg2 Start2 @inheritdoc End2 + * @param arg3 Start3 ShouldWarn @inheritdoc End3 + * @tparam T StartT @inheritdoc EndT + * @tparam ShouldWarn StartSW @inheritdoc EndSW + * @throws SomeException StartEx @inheritdoc EndEx + * @throws SomeOtherException StartSOE Should Warn @inheritdoc EndSOE + * @return StartRet @inheritdoc EndRet + * @see StartSee @inheritdoc EndSee + * @note StartNote @inheritdoc EndNote + * @example StartExample @inheritdoc EndExample + * @author StartAuthor @inheritdoc EndAuthor + * @version StartVer @inheritdoc EndVer + * @since StartSince @inheritdoc EndSince + * @todo StartTodo @inheritdoc And dad! EndTodo + */ + override def function[T](arg1: T, arg2: String): Double = 1.0d +}
\ No newline at end of file diff --git a/test/scaladoc/resources/explicit-inheritance-usecase.scala b/test/scaladoc/resources/explicit-inheritance-usecase.scala new file mode 100644 index 0000000000..e10cec437a --- /dev/null +++ b/test/scaladoc/resources/explicit-inheritance-usecase.scala @@ -0,0 +1,47 @@ +// This tests the implicit comment inheritance capabilities of scaladoc for usecases (no $super, no @inheritdoc) +/** Testing use case inheritance */ +class UseCaseInheritDoc { + /** + * The base comment. And another sentence... + * + * @param arg1 The T term comment + * @param arg2 The string comment + * @tparam T the type of the first argument + * @throws SomeException if the function is not called with correct parameters + * @return The return comment + * @see The Manual + * @note Be careful! + * @example function[Int](3, "something") + * @author a Scala developer + * @version 0.0.2 + * @since 0.0.1 + * @todo Call mom. + * + * @usecase def function[T](arg1: T, arg2: String): Double + * + * Starting line + * + * @inheritdoc + * @inheritdoc + * + * Ending line + * + * @param arg1 Start1 @inheritdoc End1 + * @param arg2 Start2 @inheritdoc End2 + * @param arg3 Start3 ShouldWarn @inheritdoc End3 + * @tparam T StartT @inheritdoc EndT + * @tparam ShouldWarn StartSW @inheritdoc EndSW + * @throws SomeException StartEx @inheritdoc EndEx + * @throws SomeOtherException StartSOE Should Warn @inheritdoc EndSOE + * @return StartRet @inheritdoc EndRet + * @see StartSee @inheritdoc EndSee + * @note StartNote @inheritdoc EndNote + * @example StartExample @inheritdoc EndExample + * @author StartAuthor @inheritdoc EndAuthor + * @version StartVer @inheritdoc EndVer + * @since StartSince @inheritdoc EndSince + * @todo StartTodo @inheritdoc And dad! EndTodo + */ + def function[T](implicit arg1: T, arg2: String): Double = 0.0d +} + diff --git a/test/scaladoc/resources/implicit-inheritance-override.scala b/test/scaladoc/resources/implicit-inheritance-override.scala index 85b8e8d543..5d692f59ad 100644 --- a/test/scaladoc/resources/implicit-inheritance-override.scala +++ b/test/scaladoc/resources/implicit-inheritance-override.scala @@ -2,12 +2,12 @@ class Base { /** * The base comment. And another sentence... - * - * @param arg1 The T term comment - * @param arg2 The string comment + * + * @param arg1 The T term comment + * @param arg2 The string comment * @tparam T the type of the first argument * @return The return comment - */ + */ def function[T](arg1: T, arg2: String): Double = 0.0d } diff --git a/test/scaladoc/resources/inheritdoc-corner-cases.scala b/test/scaladoc/resources/inheritdoc-corner-cases.scala new file mode 100644 index 0000000000..8cd995e605 --- /dev/null +++ b/test/scaladoc/resources/inheritdoc-corner-cases.scala @@ -0,0 +1,78 @@ +// TEST1: Inherit from multiple classes +trait A { + /** + * Hello 1 comment + */ + def hello1 = 0 +} + +trait B { + /** + * Hello 2 comment + */ + def hello2 = 1 +} + +trait C extends B + +class D extends A with C { + /** + * Inherited: @inheritdoc + */ + override def hello1 = super.hello2 + + /** + * Inherited: @inheritdoc + */ + override def hello2 = super.hello1 +} + +// TEST2: Invalid inherit: no parents +trait E { + /** + * @inheritdoc + */ + def whereDidThisComeFrom +} + +// TEST3: Invalid inherit, but other parents present +trait F extends E { + /** + * @inheritdoc + */ + def howAboutThis +} + + +// TEST4: Inherit from something that inherits: inherit should propagate +trait G extends D { + /** + * @inheritdoc + */ + override def hello1 = 13 + + /** + * @inheritdoc + */ + override def hello2 = 14 +} + +// TEST5: Inherit missing parameters +trait H extends G { + /** + * Missing params + * @throws HelloException @inheritdoc + * @todo @inheritdoc + */ + override def hello1 = 15 +} + +// TEST6: Inherit from something that inherits in the usecase +trait I extends G { + /** + * @inheritdoc + * @usecase def hello1(i: Int) + * @inheritdoc + */ + override def hello1 = 13 +}
\ No newline at end of file diff --git a/test/scaladoc/scala/html/HtmlFactoryTest.scala b/test/scaladoc/scala/html/HtmlFactoryTest.scala index 37aa302ac7..ead7c9e99c 100644 --- a/test/scaladoc/scala/html/HtmlFactoryTest.scala +++ b/test/scaladoc/scala/html/HtmlFactoryTest.scala @@ -21,9 +21,9 @@ object XMLUtil { } object Test extends Properties("HtmlFactory") { - - final val RESOURCES = "test/scaladoc/resources/" - + + final val RESOURCES = "test/scaladoc/resources/" + import scala.tools.nsc.doc.{DocFactory, Settings} import scala.tools.nsc.doc.model.IndexModelFactory import scala.tools.nsc.doc.html.HtmlFactory @@ -87,7 +87,7 @@ object Test extends Properties("HtmlFactory") { /** * This tests the text without the markup - ex: - * + * * <h4 class="signature"> * <span class="modifier_kind"> * <span class="modifier">implicit</span> @@ -97,24 +97,24 @@ object Test extends Properties("HtmlFactory") { * <span class="name">test</span><span class="params">()</span><span class="result">: <span name="scala.Int" class="extype">Int</span></span> * </span> * </h4> - * + * * becomes: - * + * * implicit def test(): Int - * + * * and is required to contain the text in the given checks - * + * * NOTE: Comparison is done ignoring all whitespace */ def checkText(scalaFile: String, debug: Boolean = true)(checks: (Option[String], String, Boolean)*): Boolean = { - val htmlFile = scalaFile.stripSuffix(".scala") + ".html" + val htmlFile = scalaFile.stripSuffix(".scala") + ".html" val htmlAllFiles = createTemplates(scalaFile) var result = true - + for ((fileHint, check, expected) <- checks) { // resolve the file to be checked val fileName = fileHint match { - case Some(file) => + case Some(file) => if (file endsWith ".html") file else @@ -122,20 +122,27 @@ object Test extends Properties("HtmlFactory") { case None => htmlFile } - val fileText = htmlAllFiles(fileName).text.replace('→',' ').replaceAll("\\s+","") - val checkText = check.replace('→',' ').replaceAll("\\s+","") + val fileTextPretty = htmlAllFiles(fileName).text.replace('→',' ').replaceAll("\\s+"," ") + val fileText = fileTextPretty.replaceAll(" ", "") + + val checkTextPretty = check.replace('→',' ').replaceAll("\\s+"," ") + val checkText = checkTextPretty.replaceAll(" ", "") + val checkValue = fileText.contains(checkText) == expected if (debug && (!checkValue)) { - Console.err.println("Check failed: ") - Console.err.println("HTML: " + fileText) - Console.err.println("Check: " + checkText) + Console.err.println("") + Console.err.println("HTML Check failed for resource file " + scalaFile + ":") + Console.err.println("Could not match: \n" + checkTextPretty) + Console.err.println("In the extracted HTML text: \n" + fileTextPretty) + Console.err.println("NOTE: The whitespaces are eliminated before matching!") + Console.err.println("") } - result &&= checkValue + result &&= checkValue } - + result } - + def shortComments(root: scala.xml.Node) = XMLUtil.stripGroup(root).descendant.flatMap { @@ -284,7 +291,7 @@ object Test extends Properties("HtmlFactory") { case _ => false } } - + property("Trac #4420 - no whitespace at end of line") = { val files = createTemplates("Trac4420.scala") @@ -432,47 +439,46 @@ object Test extends Properties("HtmlFactory") { createTemplate("SI_4898.scala") true } - + property("Use cases should override their original members") = checkText("SI_5054_q1.scala")( (None,"""def test(): Int""", true), (None,"""def test(implicit lost: Int): Int""", false) ) - property("Use cases should keep their flags - final should not be lost") = + property("Use cases should keep their flags - final should not be lost") = checkText("SI_5054_q2.scala")((None, """final def test(): Int""", true)) - - property("Use cases should keep their flags - implicit should not be lost") = + + property("Use cases should keep their flags - implicit should not be lost") = checkText("SI_5054_q3.scala")((None, """implicit def test(): Int""", true)) - - property("Use cases should keep their flags - real abstract should not be lost") = + + property("Use cases should keep their flags - real abstract should not be lost") = checkText("SI_5054_q4.scala")((None, """abstract def test(): Int""", true)) - property("Use cases should keep their flags - traits should not be affected") = + property("Use cases should keep their flags - traits should not be affected") = checkText("SI_5054_q5.scala")((None, """def test(): Int""", true)) - property("Use cases should keep their flags - traits should not be affected") = + property("Use cases should keep their flags - traits should not be affected") = checkText("SI_5054_q6.scala")((None, """abstract def test(): Int""", true)) - - property("Use case individual signature test") = + + property("Use case individual signature test") = checkText("SI_5054_q7.scala")( (None, """abstract def test2(explicit: Int): Int [use case] This takes the explicit value passed.""", true), (None, """abstract def test1(): Int [use case] This takes the implicit value in scope.""", true) ) - property("Display correct \"Definition classes\"") = - checkText("SI_5287.scala")( + property("Display correct \"Definition classes\"") = + checkText("SI_5287.scala")( (None, """def method(): Int [use case] The usecase explanation [use case] The usecase explanation Definition Classes SI_5287 SI_5287_B SI_5287_A""", true) - ) // the explanation appears twice, as small comment and full comment - - - property("Correct comment inheritance for overriding") = + ) // the explanation appears twice, as small comment and full comment + + property("Correct comment inheritance for overriding") = checkText("implicit-inheritance-override.scala")( - (Some("Base"), + (Some("Base"), """def function[T](arg1: T, arg2: String): Double The base comment. The base comment. And another sentence... @@ -481,7 +487,7 @@ object Test extends Properties("HtmlFactory") { arg2 The string comment returns The return comment """, true), - (Some("DerivedA"), + (Some("DerivedA"), """def function[T](arg1: T, arg2: String): Double Overriding the comment, the params and returns comments should stay the same. Overriding the comment, the params and returns comments should stay the same. @@ -490,21 +496,21 @@ object Test extends Properties("HtmlFactory") { arg2 The string comment returns The return comment """, true), - (Some("DerivedB"), + (Some("DerivedB"), """def function[T](arg1: T, arg2: String): Double T the type of the first argument arg1 The overridden T term comment arg2 The overridden string comment returns The return comment """, true), - (Some("DerivedC"), + (Some("DerivedC"), """def function[T](arg1: T, arg2: String): Double T the type of the first argument arg1 The T term comment arg2 The string comment returns The overridden return comment """, true), - (Some("DerivedD"), + (Some("DerivedD"), """def function[T](arg1: T, arg2: String): Double T The overriden type parameter comment arg1 The T term comment @@ -512,11 +518,11 @@ object Test extends Properties("HtmlFactory") { returns The return comment """, true) ) - + for (useCaseFile <- List("UseCaseInheritance", "UseCaseOverrideInheritance")) { - property("Correct comment inheritance for usecases") = + property("Correct comment inheritance for usecases") = checkText("implicit-inheritance-usecase.scala")( - (Some(useCaseFile), + (Some(useCaseFile), """def missing_arg[T](arg1: T): Double [use case] [use case] @@ -524,7 +530,7 @@ object Test extends Properties("HtmlFactory") { arg1 The T term comment returns The return comment """, true), - (Some(useCaseFile), + (Some(useCaseFile), """def missing_targ(arg1: Int, arg2: String): Double [use case] [use case] @@ -532,7 +538,7 @@ object Test extends Properties("HtmlFactory") { arg2 The string comment returns The return comment """, true), - (Some(useCaseFile), + (Some(useCaseFile), """def overridden_arg1[T](implicit arg1: T, arg2: String): Double [use case] [use case] @@ -541,7 +547,7 @@ object Test extends Properties("HtmlFactory") { arg2 The string comment returns The return comment """, true), - (Some(useCaseFile), + (Some(useCaseFile), """def overridden_targ[T](implicit arg1: T, arg2: String): Double [use case] [use case] @@ -550,7 +556,7 @@ object Test extends Properties("HtmlFactory") { arg2 The string comment returns The return comment """, true), - (Some(useCaseFile), + (Some(useCaseFile), """def overridden_return[T](implicit arg1: T, arg2: String): Double [use case] [use case] @@ -559,7 +565,7 @@ object Test extends Properties("HtmlFactory") { arg2 The string comment returns The overridden return comment """, true), - (Some(useCaseFile), + (Some(useCaseFile), """def added_arg[T](implicit arg1: T, arg2: String, arg3: Float): Double [use case] [use case] @@ -569,7 +575,7 @@ object Test extends Properties("HtmlFactory") { arg3 The added float comment returns The return comment """, true), - (Some(useCaseFile), + (Some(useCaseFile), """def overridden_comment[T](implicit arg1: T, arg2: String): Double [use case] The overridden comment. [use case] The overridden comment. @@ -578,9 +584,93 @@ object Test extends Properties("HtmlFactory") { arg2 The string comment returns The return comment """, true) - ) - } - + ) + } + + property("Correct explicit inheritance for override") = + checkText("explicit-inheritance-override.scala")( + (Some("InheritDocDerived"), + """def function[T](arg1: T, arg2: String): Double + Starting line + Starting line + The base comment. And another sentence... + The base comment. And another sentence... + Ending line + T StartT the type of the first argument EndT + arg1 Start1 The T term comment End1 + arg2 Start2 The string comment End2 + returns StartRet The return comment EndRet + Definition Classes InheritDocDerived → InheritDocBase + Example: StartExample function[Int](3, "something") EndExample + Version StartVer 0.0.2 EndVer + Since StartSince 0.0.1 EndSince + Exceptions thrown + SomeException StartEx if the function is not called with correct parameters EndEx + SomeOtherException StartSOE Should Warn <invalid inheritdoc annotation> EndSOE + To do StartTodo Call mom. And dad! EndTodo + Note StartNote Be careful! EndNote + See also StartSee The Manual EndSee + """, true)) + + property("Correct explicit inheritance for usecase") = + checkText("explicit-inheritance-usecase.scala")( + (Some("UseCaseInheritDoc"), + """def function[T](arg1: T, arg2: String): Double + [use case] Starting line + [use case] Starting line + The base comment. And another sentence... + The base comment. And another sentence... + Ending line + T StartT the type of the first argument EndT + arg1 Start1 The T term comment End1 + arg2 Start2 The string comment End2 + returns StartRet The return comment EndRet + Example: StartExample function[Int](3,"something") EndExample + Version StartVer 0.0.2 EndVer + Since StartSince 0.0.1 EndSince + Exceptions thrown + SomeException StartEx if the function is not called with correct parameters EndEx + SomeOtherException StartSOE Should Warn <invalid inheritdoc annotation> EndSOE + To do StartTodo Call mom. And dad! EndTodo + Note StartNote Be careful! EndNote + See also StartSee The Manual EndSee + """, true)) + + property("Correct explicit inheritance in corner cases") = + checkText("inheritdoc-corner-cases.scala")( + (Some("D"), + """def hello1: Int + Inherited: Hello 1 comment + Inherited: Hello 1 comment + Definition Classes D → A + """, true), + (Some("D"), + """def hello2: Int + Inherited: Hello 2 comment + Inherited: Hello 2 comment + Definition Classes D → B + """, true), + (Some("G"), + """def hello1: Int + Inherited: Hello 1 comment + Inherited: Hello 1 comment + Definition Classes G → D → A + """, true), + (Some("G"), + """def hello2: Int + Inherited: Hello 2 comment + Inherited: Hello 2 comment + Definition Classes G → D → B + """, true), + (Some("I"), + """def hello1(i: Int): Unit + [use case] Inherited: Hello 1 comment + [use case] Inherited: Hello 1 comment + Definition Classes I → G → D → A + """, true) + // traits E, F and H shouldn't crash scaladoc but we don't need to check the output + ) + { val files = createTemplates("basic.scala") //println(files) |