summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/doc/model/comment/Body.scala13
-rw-r--r--src/compiler/scala/tools/nsc/doc/model/comment/Comment.scala35
-rw-r--r--src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala2
-rw-r--r--test/scaladoc/resources/Trac4366.scala8
-rw-r--r--test/scaladoc/scala/html/HtmlFactoryTest.scala26
-rw-r--r--test/scaladoc/scala/model/CommentFactoryTest.scala30
6 files changed, 111 insertions, 3 deletions
diff --git a/src/compiler/scala/tools/nsc/doc/model/comment/Body.scala b/src/compiler/scala/tools/nsc/doc/model/comment/Body.scala
index dd2093a88e..52ef154325 100644
--- a/src/compiler/scala/tools/nsc/doc/model/comment/Body.scala
+++ b/src/compiler/scala/tools/nsc/doc/model/comment/Body.scala
@@ -67,7 +67,18 @@ final case class Link(target: String, title: Inline) extends Inline
final case class EntityLink(target: TemplateEntity) extends Inline
final case class Monospace(text: String) extends Inline
final case class Text(text: String) extends Inline
-final case class HtmlTag(data: String) extends Inline
+final case class HtmlTag(data: String) extends Inline {
+ def canClose(open: HtmlTag) = {
+ open.data.stripPrefix("<") == data.stripPrefix("</")
+ }
+
+ def close = {
+ if (data.indexOf("</") == -1)
+ Some(HtmlTag("</" + data.stripPrefix("<")))
+ else
+ None
+ }
+}
/** The summary of a comment, usually its first sentence. There must be exactly one summary per body. */
final case class Summary(text: Inline) extends Inline
diff --git a/src/compiler/scala/tools/nsc/doc/model/comment/Comment.scala b/src/compiler/scala/tools/nsc/doc/model/comment/Comment.scala
index e39907ac55..b3033188e9 100644
--- a/src/compiler/scala/tools/nsc/doc/model/comment/Comment.scala
+++ b/src/compiler/scala/tools/nsc/doc/model/comment/Comment.scala
@@ -18,8 +18,41 @@ abstract class Comment {
/** The main body of the comment that describes what the entity does and is. */
def body: Body
+ private def closeHtmlTags(inline: Inline) = {
+ val stack = mutable.ListBuffer.empty[HtmlTag]
+ def scan(i: Inline): Unit = {
+ i match {
+ case Chain(list) =>
+ list.foreach(scan)
+ case tag: HtmlTag => {
+ if (stack.length > 0 && tag.canClose(stack.last)) {
+ stack.remove(stack.length-1)
+ } else {
+ tag.close match {
+ case Some(t) =>
+ stack += t
+ case None =>
+ ;
+ }
+ }
+ }
+ case _ =>
+ ;
+ }
+ }
+ scan(inline)
+ Chain(List(inline) ++ stack.reverse)
+ }
+
/** A shorter version of the body. Usually, this is the first sentence of the body. */
- def short: Inline = body.summary getOrElse Text("")
+ def short: Inline = {
+ body.summary match {
+ case Some(s) =>
+ closeHtmlTags(s)
+ case _ =>
+ Text("")
+ }
+ }
/** A list of authors. The empty list is used when no author is defined. */
def authors: List[Body]
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 d82d5bfa5a..7485533641 100644
--- a/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala
+++ b/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala
@@ -172,7 +172,7 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory =>
/** Safe HTML tags that can be kept. */
protected val SafeTags =
- new Regex("""((&\w+;)|(&#\d+;)|(<code( [^>]*)?>.*</code>)|(</?(abbr|acronym|address|area|a|bdo|big|blockquote|br|button|b|caption|cite|col|colgroup|dd|del|dfn|em|fieldset|form|hr|img|input|ins|i|kbd|label|legend|link|map|object|optgroup|option|param|pre|q|samp|select|small|span|strong|sub|sup|table|tbody|td|textarea|tfoot|th|thead|tr|tt|var)( [^>]*)?/?>))""")
+ new Regex("""((&\w+;)|(&#\d+;)|(<code( [^>]*)?>.*?</code>)|(</?(abbr|acronym|address|area|a|bdo|big|blockquote|br|button|b|caption|cite|col|colgroup|dd|del|dfn|em|fieldset|form|hr|img|input|ins|i|kbd|label|legend|link|map|object|optgroup|option|param|pre|q|samp|select|small|span|strong|sub|sup|table|tbody|td|textarea|tfoot|th|thead|tr|tt|var)( [^>]*)?/?>))""")
protected val safeTagMarker = '\u000E'
diff --git a/test/scaladoc/resources/Trac4366.scala b/test/scaladoc/resources/Trac4366.scala
new file mode 100644
index 0000000000..d117ffa903
--- /dev/null
+++ b/test/scaladoc/resources/Trac4366.scala
@@ -0,0 +1,8 @@
+class Trac4366 {
+ /**
+ * <strong><code>foo</code> has been deprecated and will be removed in a future version of
+ * ScalaTest. Please call <code>bar</code> instead.</strong>
+ */
+ @deprecated // deprecated in 1.0, remove in 1.4
+ val foo: Option[String] = None
+}
diff --git a/test/scaladoc/scala/html/HtmlFactoryTest.scala b/test/scaladoc/scala/html/HtmlFactoryTest.scala
index f0f1cd7e49..ecdbb3cf46 100644
--- a/test/scaladoc/scala/html/HtmlFactoryTest.scala
+++ b/test/scaladoc/scala/html/HtmlFactoryTest.scala
@@ -98,4 +98,30 @@ object Test extends Properties("HtmlFactory") {
val files = createTemplates("Trac4306.scala")
files("com/example/trac4306/foo/package$$Bar.html") != None
}
+
+ property("Trac #4366") = {
+ val files = createTemplates("Trac4366.scala")
+ files("Trac4366.html") match {
+ case node: scala.xml.Node => {
+ val comments = XMLUtil.stripGroup(node).descendant.flatMap {
+ case e: scala.xml.Elem => {
+ if (e.attribute("class").toString.contains("shortcomment")) {
+ Some(e)
+ } else {
+ None
+ }
+ }
+ case _ => None
+ }
+
+ comments.exists {
+ (e) => {
+ val s = e.toString
+ s.contains("<code>foo</code>") && s.contains("</strong>")
+ }
+ }
+ }
+ case _ => false
+ }
+ }
}
diff --git a/test/scaladoc/scala/model/CommentFactoryTest.scala b/test/scaladoc/scala/model/CommentFactoryTest.scala
index afe27dace0..25a91b1fa2 100644
--- a/test/scaladoc/scala/model/CommentFactoryTest.scala
+++ b/test/scaladoc/scala/model/CommentFactoryTest.scala
@@ -18,6 +18,9 @@ class Factory(val g: Global, val s: doc.Settings)
def parseComment(s: String): Option[Inline] =
strip(parse(s, "", scala.tools.nsc.util.NoPosition))
+
+ def createBody(s: String) =
+ parse(s, "", scala.tools.nsc.util.NoPosition).body
}
object Test extends Properties("CommentFactory") {
@@ -95,4 +98,31 @@ object Test extends Properties("CommentFactory") {
Text("\n"),
HtmlTag("</pre>")))))))
)
+
+ property("Trac #4366 - body") = {
+ val body = factory.createBody(
+ """
+ /**
+ * <strong><code>foo</code> has been deprecated and will be removed in a future version. Please call <code>bar</code> instead.</strong>
+ */
+ """
+ )
+
+ body == Body(List(Paragraph(Chain(List(
+ Summary(Chain(List(Chain(List(HtmlTag("<strong>"), HtmlTag("<code>foo</code>"), Text(" has been deprecated and will be removed in a future version"))), Text(".")))),
+ Chain(List(Text(" Please call "), HtmlTag("<code>bar</code>"), Text(" instead."), HtmlTag("</strong>"), Text("\n"), Text("")))
+ )))))
+ }
+
+ property("Trac #4366 - summary") = {
+ val body = factory.createBody(
+ """
+ /**
+ * <strong><code>foo</code> has been deprecated and will be removed in a future version. Please call <code>bar</code> instead.</strong>
+ */
+ """
+ )
+
+ body.summary == Some(Chain(List(Chain(List(HtmlTag("<strong>"), HtmlTag("<code>foo</code>"), Text(" has been deprecated and will be removed in a future version"))), Text("."))))
+ }
}